Cleaning up preferences-related code.
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryPath_parse_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/DirectoryPath_parse_Test.java
similarity index 89%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryPath_parse_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/DirectoryPath_parse_Test.java
index 7dc12eb..3cbd0e4 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryPath_parse_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/DirectoryPath_parse_Test.java
@@ -6,13 +6,15 @@
  *
  * http://www.eclipse.org/legal/epl-v10.html
  */
-package com.google.eclipse.protobuf.ui.preferences.paths;
+package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertThat;
 
 import org.junit.Test;
 
+import com.google.eclipse.protobuf.ui.preferences.pages.paths.DirectoryPath;
+
 /**
  * Tests for <code>{@link DirectoryPath#parse(String)}</code>
  * 
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryPath_toString_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/DirectoryPath_toString_Test.java
similarity index 88%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryPath_toString_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/DirectoryPath_toString_Test.java
index c387983..750272d 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryPath_toString_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/DirectoryPath_toString_Test.java
@@ -6,13 +6,15 @@
  *
  * http://www.eclipse.org/legal/epl-v10.html
  */
-package com.google.eclipse.protobuf.ui.preferences.paths;
+package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertThat;
 
 import org.junit.Test;
 
+import com.google.eclipse.protobuf.ui.preferences.pages.paths.DirectoryPath;
+
 /**
  * Tests for <code>{@link DirectoryPath#toString()}</code>
  * 
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/ProjectVariable_useProjectName_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/ProjectVariable_useProjectName_Test.java
similarity index 91%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/ProjectVariable_useProjectName_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/ProjectVariable_useProjectName_Test.java
index d03094f..13c59db 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/ProjectVariable_useProjectName_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/ProjectVariable_useProjectName_Test.java
@@ -6,13 +6,13 @@
  *
  * http://www.eclipse.org/legal/epl-v10.html
  */
-package com.google.eclipse.protobuf.ui.preferences.paths;
+package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.*;
 
-import com.google.eclipse.protobuf.ui.preferences.paths.ProjectVariable;
+import com.google.eclipse.protobuf.ui.preferences.pages.paths.ProjectVariable;
 
 import org.eclipse.core.resources.IProject;
 import org.junit.*;
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/ProjectVariable_useProjectVariable_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/ProjectVariable_useProjectVariable_Test.java
similarity index 92%
rename from com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/ProjectVariable_useProjectVariable_Test.java
rename to com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/ProjectVariable_useProjectVariable_Test.java
index 36fed91..96c9c7d 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/paths/ProjectVariable_useProjectVariable_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/ProjectVariable_useProjectVariable_Test.java
@@ -6,13 +6,13 @@
  *
  * http://www.eclipse.org/legal/epl-v10.html
  */
-package com.google.eclipse.protobuf.ui.preferences.paths;
+package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.*;
 
-import com.google.eclipse.protobuf.ui.preferences.paths.ProjectVariable;
+import com.google.eclipse.protobuf.ui.preferences.pages.paths.ProjectVariable;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.*;
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver_resolveUri_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver_resolveUri_Test.java
index 6ec8b87..737370f 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver_resolveUri_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver_resolveUri_Test.java
@@ -17,7 +17,7 @@
 import org.eclipse.emf.common.util.URI;
 import org.junit.*;
 
-import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferences;
+import com.google.eclipse.protobuf.ui.preferences.pages.paths.PathsPreferences;
 import com.google.eclipse.protobuf.ui.util.Resources;
 
 /**
diff --git a/com.google.eclipse.protobuf.ui/plugin.xml b/com.google.eclipse.protobuf.ui/plugin.xml
index 7f6628a..ee1e0c4 100644
--- a/com.google.eclipse.protobuf.ui/plugin.xml
+++ b/com.google.eclipse.protobuf.ui/plugin.xml
@@ -48,7 +48,7 @@
   </extension>
   <extension point="org.eclipse.ui.preferencePages">
     <page
-      class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.general.GeneralSettingsPreferencePage"
+      class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.pages.general.GeneralSettingsPreferencePage"
       id="com.google.eclipse.protobuf.Protobuf" name="%page.name">
       <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf" />
     </page>
@@ -57,14 +57,14 @@
       id="com.google.eclipse.protobuf.Protobuf.coloring" name="%page.name.0">
       <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf" />
     </page>
-    <page category="com.google.eclipse.protobuf.Protobuf"
+    <!--page category="com.google.eclipse.protobuf.Protobuf"
       class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:org.eclipse.xtext.ui.editor.templates.XtextTemplatePreferencePage"
       id="com.google.eclipse.protobuf.Protobuf.templates" name="%page.name.1">
       <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf" />
-    </page>
+    </page-->
     <page category="com.google.eclipse.protobuf.Protobuf"
-      class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferencePage"
-      id="com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferencePage" name="%page.name.2">
+      class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.pages.compiler.CompilerPreferencePage"
+      id="com.google.eclipse.protobuf.ui.preferences.pages.compiler.CompilerPreferencePage" name="%page.name.2">
       <keywordReference id="com.google.eclipse.protobuf.ui.keyword_Protobuf" />
     </page>
   </extension>
@@ -161,20 +161,20 @@
   </extension>
   <extension point="org.eclipse.ui.propertyPages">
     <page
-      class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.general.GeneralSettingsPreferencePage"
+      class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.pages.general.GeneralSettingsPreferencePage"
       id="com.google.eclipse.protobuf.Protobuf"
       name="%page.name" selectionFilter="single">
     </page>
     <page
           category="com.google.eclipse.protobuf.Protobuf"
-          class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferencePage"
+          class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.pages.compiler.CompilerPreferencePage"
           id="com.google.eclipse.protobuf.ui.properties.compiler.PropertyPage"
           name="%page.name.2"
           selectionFilter="single">
     </page>
     <page
           category="com.google.eclipse.protobuf.Protobuf"
-          class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferencePage"
+          class="com.google.eclipse.protobuf.ui.ProtobufExecutableExtensionFactory:com.google.eclipse.protobuf.ui.preferences.pages.paths.PathsPreferencePage"
           id="com.google.eclipse.protobuf.ui.properties.paths.PropertyPage"
           name="%page.name.3"
           selectionFilter="single">
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/OutputDirectories.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/OutputDirectories.java
index a2b2214..884c12e 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/OutputDirectories.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/OutputDirectories.java
@@ -24,17 +24,17 @@
 
   private final Map<SupportedLanguage, IFolder> outputDirectories = new HashMap<SupportedLanguage, IFolder>();
 
-  static OutputDirectories findOrCreateOutputDirectories(IProject project, List<CodeGeneration> preferences)
+  static OutputDirectories findOrCreateOutputDirectories(IProject project, CodeGenerationSettings preferences)
       throws CoreException {
     Map<SupportedLanguage, IFolder> outputDirectories = new HashMap<SupportedLanguage, IFolder>();
-    for (CodeGeneration preference : preferences) {
+    for (CodeGenerationSetting preference : preferences.allSettings()) {
       if (!preference.isEnabled()) continue;
       outputDirectories.put(preference.language(), findOrCreateOutputDirectory(project, preference));
     }
     return new OutputDirectories(outputDirectories);
   }
 
-  private static IFolder findOrCreateOutputDirectory(IProject project, CodeGeneration preference)
+  private static IFolder findOrCreateOutputDirectory(IProject project, CodeGenerationSetting preference)
       throws CoreException {
     return findOrCreateOutputDirectory(project, preference.outputDirectory());
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtobufBuildParticipant.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtobufBuildParticipant.java
index d690534..e99e78e 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtobufBuildParticipant.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/ProtobufBuildParticipant.java
@@ -41,7 +41,7 @@
   @Inject private ProtocOutputParser outputParser;
   @Inject private ProtocCommandFactory commandFactory;
   @Inject private CompilerPreferencesProvider compilerPreferencesProvider;
-  @Inject private PathsPreferencesProvider pathsPreferencesProvider;
+  @Inject private PathsPreferencesFactory pathsPreferencesFactory;
 
   public void build(IBuildContext context, IProgressMonitor monitor) throws CoreException {
     IProject project = context.getBuiltProject();
@@ -49,7 +49,7 @@
     if (!preferences.shouldCompileProtoFiles()) return;
     List<Delta> deltas = context.getDeltas();
     if (deltas.isEmpty()) return;
-    OutputDirectories outputDirectories = findOrCreateOutputDirectories(project, preferences.codeGenerationOptions());
+    OutputDirectories outputDirectories = findOrCreateOutputDirectories(project, preferences.codeGenerationSettings());
     List<String> importRoots = importRoots(project);
     for (Delta d : deltas) {
       IResourceDescription newResource = d.getNew();
@@ -63,7 +63,7 @@
 
   private List<String> importRoots(IProject project) {
     List<String> paths = new ArrayList<String>();
-    PathsPreferences preferences = pathsPreferencesProvider.getPreferences(project);
+    PathsPreferences preferences = pathsPreferencesFactory.preferences(project);
     List<DirectoryPath> directoryPaths = preferences.importRoots();
     for (DirectoryPath path : directoryPaths) {
       String location = locationOfDirectory(path, project);
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/BooleanPreference.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/BooleanPreference.java
new file mode 100644
index 0000000..099ea37
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/BooleanPreference.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * A preference that stores a {@code boolean} value.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class BooleanPreference extends Preference<Boolean> {
+
+  /**
+   * Creates a new </code>{@link BooleanPreference}</code>.
+   * @param name the name of this preference.
+   * @param store the store for this preference.
+   */
+  public BooleanPreference(String name, IPreferenceStore store) {
+    super(name, store);
+  }
+
+  /** {@inheritDoc} */
+  @Override public Boolean value() {
+    return store.getBoolean(name);
+  }
+
+  /** {@inheritDoc} */
+  @Override public Boolean defaultValue() {
+    return store.getDefaultBoolean(name);
+  }
+
+  /** {@inheritDoc} */
+  @Override public void value(Boolean value) {
+    store.setValue(name, value);
+  }
+
+  /** {@inheritDoc} */
+  @Override public void defaultValue(Boolean value) {
+    store.setDefault(name, value);
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Preference.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Preference.java
new file mode 100644
index 0000000..cd3fec5
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/Preference.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * A single preference value.
+ * @param <T> the type of value this preference handles.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public abstract class Preference<T> {
+
+  protected final String name;
+  protected final IPreferenceStore store;
+
+  /**
+   * Creates a new </code>{@link Preference}</code>.
+   * @param name the name of this preference.
+   * @param store the store for this preference.
+   */
+  public Preference(String name, IPreferenceStore store) {
+    this.name = name;
+    this.store = store;
+  }
+
+  /**
+   * Returns the value of this preference.
+   * @return the value of this preference.
+   */
+  public abstract T value();
+
+  /**
+   * Returns the default value of this preference.
+   * @return the default value of this preference.
+   */
+  public abstract T defaultValue();
+
+  /**
+   * Saves the value of this preference to the given store.
+   * @param value the value to save.
+   */
+  public abstract void value(T value);
+
+  /**
+   * Saves the default value of this preference to the given store.
+   * @param value the default value to save.
+   */
+  public abstract void defaultValue(T value);
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/StringPreference.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/StringPreference.java
new file mode 100644
index 0000000..d62d429
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/StringPreference.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * A preference that stores a {@code String} value.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class StringPreference extends Preference<String> {
+
+  /**
+   * Creates a new </code>{@link StringPreference}</code>.
+   * @param name the name of this preference.
+   * @param store the store for this preference.
+   */
+  public StringPreference(String name, IPreferenceStore store) {
+    super(name, store);
+  }
+
+  /** {@inheritDoc} */
+  @Override public String value() {
+    return store.getString(name);
+  }
+
+  /** {@inheritDoc} */
+  @Override public String defaultValue() {
+    return store.getDefaultString(name);
+  }
+
+  /** {@inheritDoc} */
+  @Override public void value(String value) {
+    store.setValue(name, value);
+  }
+
+  /** {@inheritDoc} */
+  @Override public void defaultValue(String value) {
+    store.setDefault(name, value);
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/Binding.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/Binding.java
index bf52b15..feffdfb 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/Binding.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/Binding.java
@@ -9,35 +9,26 @@
 package com.google.eclipse.protobuf.ui.preferences.binding;
 
 import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.swt.widgets.Control;
 
 /**
- * Binds a value from a <code>{@link IPreferenceStore}</code> to the selection of a
- * <code>{@link Control}</code>.
+ * Binds a value from a <code>{@link IPreferenceStore}</code> to an object.
  *
  * @author alruiz@google.com (Alex Ruiz)
  */
 public interface Binding {
 
   /**
-   * Reads a preference from the given <code>{@link IPreferenceStore}</code> and applies it to this binding's
-   * <code>{@link Control}</code>.
-   * @param store the preference store.
+   * Reads a preference value and applies it to this binding's target object.
    */
-  void read(IPreferenceStore store);
+  void applyPreferenceValueToTarget();
 
   /**
-   * Reads a default value preference from the given <code>{@link IPreferenceStore}</code> and applies it to the this
-   * binding's <code>{@link Control}</code>.
-   * @param store the preference store.
+   * Reads a default value preference and applies it to the this binding's target object.
    */
-  void readDefault(IPreferenceStore store);
+  void applyDefaultPreferenceValueToTarget();
 
   /**
-   * Applies the value of this binding's <code>{@link Control}</code> to a preference in the given
-   * <code>{@link IPreferenceStore}</code>.
-   * @param store the preference store.
+   * Applies the value of this binding's target object to a preference.
    */
-  void save(IPreferenceStore store);
-
+  void savePreferenceValue();
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/BindingToButtonSelection.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/BindingToButtonSelection.java
new file mode 100644
index 0000000..c39b4e3
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/BindingToButtonSelection.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences.binding;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.widgets.Button;
+
+import com.google.eclipse.protobuf.ui.preferences.BooleanPreference;
+
+/**
+ * Binds a {@code boolean} value from a <code>{@link IPreferenceStore}</code> to the selection of a
+ * <code>{@link Button}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class BindingToButtonSelection implements Binding {
+
+  private final Button button;
+  private final BooleanPreference preference;
+
+  public static BindingBuilder bindSelectionOf(Button button) {
+    return new BindingBuilder(button);
+  }
+
+  /**
+   * Creates a new </code>{@link BindingToButtonSelection}</code>.
+   * @param button the control to bind to the preference.
+   * @param preference the given preference.
+   */
+  private BindingToButtonSelection(Button button, BooleanPreference preference) {
+    this.preference = preference;
+    this.button = button;
+  }
+
+  /** {@inheritDoc} */
+  public void applyPreferenceValueToTarget() {
+    boolean value = preference.value();
+    button.setSelection(value);
+  }
+
+  /** {@inheritDoc} */
+  public void applyDefaultPreferenceValueToTarget() {
+    boolean value = preference.defaultValue();
+    button.setSelection(value);
+  }
+
+  /** {@inheritDoc} */
+  public void savePreferenceValue() {
+    preference.value(button.getSelection());
+  }
+
+  public static class BindingBuilder {
+    private final Button button;
+
+    /**
+     * Creates a new </code>{@link BindingBuilder}</code>.
+     * @param button the button whose selection will be bound to a preference value.
+     */
+    public BindingBuilder(Button button) {
+      this.button = button;
+    }
+
+    /**
+     * Creates a new <code>{@link BindingToButtonSelection}</code>.
+     * @param preference the preference to bind to the selection of this builder's button.
+     * @return the created binding.
+     */
+    public BindingToButtonSelection to(BooleanPreference preference) {
+      return new BindingToButtonSelection(button, preference);
+    }
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/BindingToTextValue.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/BindingToTextValue.java
new file mode 100644
index 0000000..92c2e5b
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/BindingToTextValue.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences.binding;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.widgets.Text;
+
+import com.google.eclipse.protobuf.ui.preferences.StringPreference;
+
+/**
+ * Binds a {@code boolean} value from a <code>{@link IPreferenceStore}</code> to the value of a
+ * <code>{@link Text}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class BindingToTextValue implements Binding {
+
+  private final Text text;
+  private final StringPreference preference;
+
+  public static BindingBuilder bindTextOf(Text text) {
+    return new BindingBuilder(text);
+  }
+
+  /**
+   * Creates a new </code>{@link BindingToTextValue}</code>.
+   * @param text the control to bind to the preference.
+   * @param preference the given preference.
+   */
+  private BindingToTextValue(Text text, StringPreference preference) {
+    this.text = text;
+    this.preference = preference;
+  }
+
+  /** {@inheritDoc} */
+  public void applyPreferenceValueToTarget() {
+    String value = preference.value();
+    text.setText(value);
+  }
+
+  /** {@inheritDoc} */
+  public void applyDefaultPreferenceValueToTarget() {
+    String value = preference.defaultValue();
+    text.setText(value);
+  }
+
+  /** {@inheritDoc} */
+  public void savePreferenceValue() {
+    preference.value(text.getText());
+  }
+
+  public static class BindingBuilder {
+    private final Text text;
+
+    /**
+     * Creates a new </code>{@link BindingBuilder}</code>.
+     * @param text the text whose value will be bound to a preference value.
+     */
+    public BindingBuilder(Text text) {
+      this.text = text;
+    }
+
+    /**
+     * Creates a new <code>{@link BindingToTextValue}</code>.
+     * @param preference the preference to bind to the value of this builder's text.
+     * @return the created binding.
+     */
+    public BindingToTextValue to(StringPreference preference) {
+      return new BindingToTextValue(text, preference);
+    }
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/PreferenceBinder.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/PreferenceBinder.java
index b31b6d5..d058473 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/PreferenceBinder.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/PreferenceBinder.java
@@ -10,9 +10,6 @@
 
 import java.util.*;
 
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.swt.widgets.Button;
-
 /**
  * Binds preferences to UI controls.
  *
@@ -20,31 +17,31 @@
  */
 public class PreferenceBinder {
 
-  private final List<Binding> bindings = new ArrayList<Binding>();
+  private final List<Binding> allBindings = new ArrayList<Binding>();
 
-  public void bind(String preferenceName, Button button) {
-    add(new PreferenceToButtonBinding(preferenceName, button));
+  public void addAll(Binding...bindings) {
+    for (Binding binding : bindings) add(binding);
   }
 
   public void add(Binding binding) {
-    bindings.add(binding);
+    allBindings.add(binding);
   }
 
-  public void readPreferences(IPreferenceStore store) {
-    for (Binding binding : bindings) {
-      binding.read(store);
+  public void applyValues() {
+    for (Binding binding : allBindings) {
+      binding.applyPreferenceValueToTarget();
     }
   }
 
-  public void readDefaultPreferences(IPreferenceStore store) {
-    for (Binding binding : bindings) {
-      binding.readDefault(store);
+  public void applyDefaults() {
+    for (Binding binding : allBindings) {
+      binding.applyDefaultPreferenceValueToTarget();
     }
   }
 
-  public void savePreferences(IPreferenceStore store) {
-    for (Binding binding : bindings) {
-      binding.save(store);
+  public void saveValues() {
+    for (Binding binding : allBindings) {
+      binding.savePreferenceValue();
     }
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/PreferenceToButtonBinding.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/PreferenceToButtonBinding.java
deleted file mode 100644
index f3eee93..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/binding/PreferenceToButtonBinding.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.ui.preferences.binding;
-
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.swt.widgets.Button;
-
-/**
- * Binds a {@code boolean} value from a <code>{@link IPreferenceStore}</code> to the selection of a
- * <code>{@link Button}</code>.
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class PreferenceToButtonBinding implements Binding {
-
-  private final String preferenceName;
-  private final Button button;
-
-  /**
-   * Creates a new </code>{@link PreferenceToButtonBinding}</code>.
-   * @param preferenceName the name of the preference to read/write.
-   * @param button the control to bind to the preference.
-   */
-  public PreferenceToButtonBinding(String preferenceName, Button button) {
-    this.preferenceName = preferenceName;
-    this.button = button;
-  }
-
-  /**
-   * Reads a {@code boolean} preference from the given <code>{@link IPreferenceStore}</code> and applies it to the
-   * selection of this binding's button.
-   * @param store the preference store.
-   */
-  public void read(IPreferenceStore store) {
-    boolean value = store.getBoolean(preferenceName);
-    button.setSelection(value);
-  }
-
-  /**
-   * Reads the default {@code boolean} preference value from the given <code>{@link IPreferenceStore}</code> and applies
-   * it to the selection of this binding's button.
-   * @param store the preference store.
-   */
-  public void readDefault(IPreferenceStore store) {
-    boolean value = store.getDefaultBoolean(preferenceName);
-    button.setSelection(value);
-  }
-
-  /**
-   * Applies the value of the selection of this binding's button to a preference in the given
-   * <code>{@link IPreferenceStore}</code>.
-   * @param store the preference store.
-   */
-  public void save(IPreferenceStore store) {
-    store.setValue(preferenceName, button.getSelection());
-  }
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/PreferenceAndPropertyPage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/PreferenceAndPropertyPage.java
index bfdc354..6105f8b 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/PreferenceAndPropertyPage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/PreferenceAndPropertyPage.java
@@ -23,6 +23,7 @@
 import org.eclipse.ui.*;
 import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
 
+import com.google.eclipse.protobuf.ui.preferences.binding.PreferenceBinder;
 import com.google.inject.Inject;
 
 /**
@@ -32,7 +33,8 @@
  */
 public abstract class PreferenceAndPropertyPage extends PreferencePage implements IWorkbenchPreferencePage, IWorkbenchPropertyPage {
 
-  private Button btnEnableProjectSettings;
+  protected Button btnEnableProjectSettings;
+
   private Link lnkEnableWorkspaceSettings;
 
   private IProject project;
@@ -40,13 +42,29 @@
 
   @Inject private IPreferenceStoreAccess preferenceStoreAccess;
 
+  private final PreferenceBinder preferenceBinder = new PreferenceBinder();
+
+  @Override protected final Control createContents(Composite parent) {
+    Composite contents = contentParent(parent);
+    doCreateContents(contents);
+    setupBinding(preferenceBinder);
+    preferenceBinder.applyValues();
+    onPageCreation();
+    return contents;
+  }
+
   /**
-   * Creates the <code>{@link Composite}</code> that contains the options to switch between "Project" and "Workspace"
-   * settings.
+   * Creates the <code>{@link Composite}</code> that will contain all the UI controls in this preference page. By
+   * default it returns a <code>{@link Composite}</code> that contains the options to switch between "Project" and
+   * "Workspace" settings.
    * @param parent the parent {@code Composite}.
    * @return the created {@code Composite}.
    */
-  protected final Composite switchBetweenProjectAndWorkspaceSettings(Composite parent) {
+  protected Composite contentParent(Composite parent) {
+    return switchBetweenProjectAndWorkspaceSettings(parent);
+  }
+
+  private Composite switchBetweenProjectAndWorkspaceSettings(Composite parent) {
     // generated by WindowBuilder
     Composite contents = new Composite(parent, NONE);
     contents.setLayout(new GridLayout(3, false));
@@ -94,6 +112,21 @@
   }
 
   /**
+   * Creates the contents of this preference page.
+   * @param parent the parent {@code Composite}.
+   */
+  protected abstract void doCreateContents(Composite parent);
+
+  /**
+   * Sets up data binding.
+   * @param preferenceBinder the preference binder;
+   */
+  protected abstract void setupBinding(PreferenceBinder preferenceBinder);
+
+  /** Method invoked after the page has been created. By default this method does nothing. */
+  protected void onPageCreation() {}
+
+  /**
    * Returns the id of this preference page.
    * @return the id of this preference page.
    */
@@ -170,30 +203,24 @@
   public void init(IWorkbench workbench) {}
 
   @Override public final boolean performOk() {
-    savePreferences(getPreferenceStore());
+    preferenceBinder.saveValues();
+    okPerformed();
     return true;
   }
 
-  /**
-   * Saves the current settings.
-   * @param store the preference store used by this page.
-   */
-  protected abstract void savePreferences(IPreferenceStore store);
+  /** Method invoked after this page's defaults have been saved. By default this method does nothing. */
+  protected void okPerformed() {}
 
   @Override protected final void performDefaults() {
-    performDefaults(getPreferenceStore());
+    preferenceBinder.applyDefaults();
+    defaultsPerformed();
     super.performDefaults();
   }
 
-  /**
-   * Performs special processing when this page's "Defaults" button has been pressed.
-   * @param store the preference store used by this page.
-   */
-  protected abstract void performDefaults(IPreferenceStore store);
+  /** Method invoked after this page's defaults have been processed. By default this method does nothing. */
+  protected void defaultsPerformed() {}
 
-  /**
-   * Marks this page as "valid."
-   */
+  /** Marks this page as "valid." */
   protected final void pageIsNowValid() {
     setErrorMessage(null);
     setValid(true);
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/BindingToCodeGeneration.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/BindingToCodeGeneration.java
new file mode 100644
index 0000000..2985002
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/BindingToCodeGeneration.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
+
+import com.google.eclipse.protobuf.ui.preferences.*;
+import com.google.eclipse.protobuf.ui.preferences.binding.Binding;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class BindingToCodeGeneration implements Binding {
+
+  private final CodeGenerationSetting codeGeneration;
+  private final BooleanPreference enabled;
+  private final StringPreference outputDirectory;
+
+  static BindingBuilder bindCodeGeneration(CodeGenerationSetting codeGeneration) {
+    return new BindingBuilder(codeGeneration);
+  }
+
+  private BindingToCodeGeneration(CodeGenerationSetting codeGeneration, BooleanPreference enabled, StringPreference outputDirectory) {
+    this.codeGeneration = codeGeneration;
+    this.enabled = enabled;
+    this.outputDirectory = outputDirectory;
+  }
+
+  /** {@inheritDoc} */
+  public void applyPreferenceValueToTarget() {
+    codeGeneration.enabled(enabled.value());
+    codeGeneration.outputDirectory(outputDirectory.value());
+  }
+
+  /** {@inheritDoc} */
+  public void applyDefaultPreferenceValueToTarget() {
+    codeGeneration.enabled(enabled.defaultValue());
+    codeGeneration.outputDirectory(outputDirectory.defaultValue());
+  }
+
+  /** {@inheritDoc} */
+  public void savePreferenceValue() {
+    enabled.value(codeGeneration.isEnabled());
+    outputDirectory.value(codeGeneration.outputDirectory());
+  }
+
+  static class BindingBuilder {
+    private final CodeGenerationSetting codeGeneration;
+
+    BindingBuilder(CodeGenerationSetting codeGeneration) {
+      this.codeGeneration = codeGeneration;
+    }
+
+    BindingToCodeGeneration to(BooleanPreference enabled, StringPreference outputDirectory) {
+      return new BindingToCodeGeneration(codeGeneration, enabled, outputDirectory);
+    }
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationEditor.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationEditor.java
index 49e42f6..0449722 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationEditor.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationEditor.java
@@ -37,7 +37,7 @@
   private final TableViewer tblVwrCodeGenerationOptions;
   private final Button btnEdit;
 
-  private final List<CodeGeneration> options = new ArrayList<CodeGeneration>();
+  private final List<CodeGenerationSetting> settings = new ArrayList<CodeGenerationSetting>();
 
   private DataChangedListener dataChangedListener;
 
@@ -62,7 +62,7 @@
       }
 
       @Override public Image getImage(Object element) {
-        boolean optionEnabled = ((CodeGeneration)element).isEnabled();
+        boolean optionEnabled = ((CodeGenerationSetting)element).isEnabled();
         return imageHelper.getImage(optionEnabled ? "checked.gif" : "unchecked.gif"); //$NON-NLS-1$ //$NON-NLS-2$
       }
     });
@@ -74,7 +74,7 @@
     tblclmnLanguage.setText(language);
     tblclmnVwrLanguage.setLabelProvider(new ColumnLabelProvider() {
       @Override public String getText(Object element) {
-        return ((CodeGeneration)element).language().name();
+        return ((CodeGenerationSetting)element).language().name();
       }
     });
 
@@ -85,7 +85,7 @@
     tblclmnOutputDirectory.setText(outputDirectory);
     tblclmnVwrOutputDirectory.setLabelProvider(new ColumnLabelProvider() {
       @Override public String getText(Object element) {
-        return ((CodeGeneration)element).outputDirectory();
+        return ((CodeGenerationSetting)element).outputDirectory();
       }
     });
 
@@ -108,7 +108,7 @@
     btnEdit.addSelectionListener(new SelectionAdapter() {
       @Override public void widgetSelected(SelectionEvent e) {
         int selectionIndex = tblCodeGenerationOptions.getSelectionIndex();
-        CodeGeneration option = options.get(selectionIndex);
+        CodeGenerationSetting option = settings.get(selectionIndex);
         EditCodeGenerationDialog dialog = new EditCodeGenerationDialog(getShell(), option);
         if (dialog.open() == OK) {
           tblVwrCodeGenerationOptions.refresh();
@@ -118,19 +118,19 @@
     });
   }
 
-  public List<CodeGeneration> codeGenerationOptions() {
-    return unmodifiableList(options);
+  public List<CodeGenerationSetting> codeGenerationOptions() {
+    return unmodifiableList(settings);
   }
 
-  public void codeGenerationOptions(List<CodeGeneration> newOptions) {
-    options.clear();
-    options.addAll(newOptions);
+  public void codeGenerationSettings(List<CodeGenerationSetting> newSettings) {
+    settings.clear();
+    settings.addAll(newSettings);
     updateTable();
   }
 
   private void updateTable() {
-    tblVwrCodeGenerationOptions.setInput(options);
-    if (!options.isEmpty()) tblCodeGenerationOptions.setSelection(0);
+    tblVwrCodeGenerationOptions.setInput(settings);
+    if (!settings.isEmpty()) tblCodeGenerationOptions.setSelection(0);
   }
 
   /** {@inheritDoc} */
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationPreferencesProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationPreferencesProvider.java
deleted file mode 100644
index 8eff006..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationPreferencesProvider.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
-
-import static java.util.Collections.unmodifiableList;
-
-import java.util.*;
-
-import org.eclipse.jface.preference.IPreferenceStore;
-
-import com.google.inject.Singleton;
-
-/**
- * Reads "code generation" preferences.
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-@Singleton
-public class CodeGenerationPreferencesProvider {
-
-  public List<CodeGeneration> getPreferences(IPreferenceStore store) {
-    List<CodeGeneration> options = new ArrayList<CodeGeneration>();
-    for (SupportedLanguage language : SupportedLanguage.values()) options.add(read(store, language));
-    return unmodifiableList(options);
-  }
-
-  private static CodeGeneration read(IPreferenceStore store, SupportedLanguage language) {
-    String outputDirectory = store.getString(outputDirectoryPreferenceName(language));
-    boolean enabled = store.getBoolean(codeGenerationEnabledPreferenceName(language));
-    return new CodeGeneration(language, outputDirectory, enabled);
-  }
-
-  public List<CodeGeneration> getDefaults(IPreferenceStore store) {
-    List<CodeGeneration> options = new ArrayList<CodeGeneration>();
-    for (SupportedLanguage language : SupportedLanguage.values()) options.add(readDefault(store, language));
-    return unmodifiableList(options);
-  }
-
-  private static CodeGeneration readDefault(IPreferenceStore store, SupportedLanguage language) {
-    String outputDirectory = store.getDefaultString(outputDirectoryPreferenceName(language));
-    boolean enabled = store.getDefaultBoolean(codeGenerationEnabledPreferenceName(language));
-    return new CodeGeneration(language, outputDirectory, enabled);
-  }
-
-  public void save(IPreferenceStore store, List<CodeGeneration> options) {
-    for (CodeGeneration option : options) save(store, option);
-  }
-
-  private static void save(IPreferenceStore store, CodeGeneration option) {
-    SupportedLanguage language = option.language();
-    store.setValue(outputDirectoryPreferenceName(language), option.outputDirectory());
-    store.setValue(codeGenerationEnabledPreferenceName(language), option.isEnabled());
-  }
-
-  private static String outputDirectoryPreferenceName(SupportedLanguage language) {
-    return "compiler." + language.code() + "OutputDirectory";
-  }
-
-  private static String codeGenerationEnabledPreferenceName(SupportedLanguage language) {
-    return "compiler." + language.code() + "CodeGenerationEnabled";
-  }
-}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGeneration.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationSetting.java
similarity index 89%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGeneration.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationSetting.java
index ca93f43..f945352 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGeneration.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationSetting.java
@@ -8,23 +8,20 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
 
-
 /**
  * Indicates whether code generation for a specific language is enabled and where the generated code should be placed.
  *
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class CodeGeneration {
+public class CodeGenerationSetting {
 
   private final SupportedLanguage language;
 
   private String outputDirectory;
   private boolean enabled;
 
-  CodeGeneration(SupportedLanguage language, String outputDirectory, boolean enabled) {
+  CodeGenerationSetting(SupportedLanguage language) {
     this.language = language;
-    this.outputDirectory = outputDirectory;
-    this.enabled = enabled;
   }
 
   /**
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationSettings.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationSettings.java
new file mode 100644
index 0000000..30415e5
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CodeGenerationSettings.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
+
+import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.SupportedLanguage.*;
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableList;
+
+import java.util.List;
+
+/**
+ * All the supported <code>{@link CodeGenerationSetting}</code>s.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class CodeGenerationSettings {
+
+  private final CodeGenerationSetting java;
+  private final CodeGenerationSetting cpp;
+  private final CodeGenerationSetting python;
+
+  private final List<CodeGenerationSetting> allSettings;
+
+  CodeGenerationSettings() {
+    java = new CodeGenerationSetting(JAVA);
+    cpp = new CodeGenerationSetting(CPP);
+    python = new CodeGenerationSetting(PYTHON);
+    allSettings = unmodifiableList(asList(java, cpp, python));
+  }
+
+  /**
+   * Returns the settings for code generation using Java.
+   * @return the settings for code generation using Java.
+   */
+  public CodeGenerationSetting java() {
+    return java;
+  }
+
+  /**
+   * Returns the settings for code generation using C++.
+   * @return the settings for code generation using C++.
+   */
+  public CodeGenerationSetting cpp() {
+    return cpp;
+  }
+
+  /**
+   * Returns the settings for code generation using Python.
+   * @return the settings for code generation using Python.
+   */
+  public CodeGenerationSetting python() {
+    return python;
+  }
+
+  /**
+   * Returns all the settings for code generation using all supported languages.
+   * @return all the settings for code generation using all supported languages.
+   */
+  public List<CodeGenerationSetting> allSettings() {
+    return allSettings;
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencePage.java
index c0eea98..a76f5d6 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencePage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencePage.java
@@ -8,24 +8,26 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
 
+import static com.google.eclipse.protobuf.ui.preferences.binding.BindingToButtonSelection.bindSelectionOf;
+import static com.google.eclipse.protobuf.ui.preferences.binding.BindingToTextValue.bindTextOf;
+import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.BindingToCodeGeneration.bindCodeGeneration;
 import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.Messages.*;
-import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.PreferenceNames.*;
 import static com.google.eclipse.protobuf.ui.swt.EventListeners.addSelectionListener;
 import static java.util.Arrays.asList;
 import static org.eclipse.xtext.util.Strings.isEmpty;
 
-import com.google.eclipse.protobuf.ui.preferences.*;
-import com.google.eclipse.protobuf.ui.preferences.pages.PreferenceAndPropertyPage;
-import com.google.inject.Inject;
+import java.io.File;
 
-import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.*;
 import org.eclipse.swt.layout.*;
 import org.eclipse.swt.widgets.*;
 import org.eclipse.xtext.ui.PluginImageHelper;
 
-import java.io.File;
+import com.google.eclipse.protobuf.ui.preferences.DataChangedListener;
+import com.google.eclipse.protobuf.ui.preferences.binding.PreferenceBinder;
+import com.google.eclipse.protobuf.ui.preferences.pages.PreferenceAndPropertyPage;
+import com.google.inject.Inject;
 
 /**
  * Preference page for protobuf compiler.
@@ -50,21 +52,18 @@
   private Button btnRefreshResources;
   private Group grpRefresh;
   private Button btnRefreshProject;
-  private Button btnRefreshOutputFolder;
+  private Button btnRefreshOutputDirectory;
 
   @Inject private PluginImageHelper imageHelper;
-  @Inject private CodeGenerationPreferencesProvider codeGenerationPreferencesProvider;
 
-  /** {@inheritDoc} */
-  @Override protected Control createContents(Composite parent) {
-    // generated by WindowBuilder
-    Composite contents = switchBetweenProjectAndWorkspaceSettings(parent);
+  private final CodeGenerationSettings codeGenerationSettings = new CodeGenerationSettings();
 
-    btnCompileProtoFiles = new Button(contents, SWT.CHECK);
+  @Override protected void doCreateContents(Composite parent) {
+    btnCompileProtoFiles = new Button(parent, SWT.CHECK);
     btnCompileProtoFiles.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1));
     btnCompileProtoFiles.setText(compileOnSave);
 
-    tabFolder = new TabFolder(contents, SWT.NONE);
+    tabFolder = new TabFolder(parent, SWT.NONE);
     tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
 
     tbtmMain = new TabItem(tabFolder, SWT.NONE);
@@ -123,36 +122,12 @@
     btnRefreshProject.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
     btnRefreshProject.setText(refreshProject);
 
-    btnRefreshOutputFolder = new Button(grpRefresh, SWT.RADIO);
-    btnRefreshOutputFolder.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
-    btnRefreshOutputFolder.setText(refreshOutputProject);
-    new Label(contents, SWT.NONE);
+    btnRefreshOutputDirectory = new Button(grpRefresh, SWT.RADIO);
+    btnRefreshOutputDirectory.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+    btnRefreshOutputDirectory.setText(refreshOutputProject);
+    new Label(parent, SWT.NONE);
 
-    updateFromPreferenceStore();
     addEventListeners();
-
-    return contents;
-  }
-
-  private void updateFromPreferenceStore() {
-    IPreferenceStore store = getPreferenceStore();
-    boolean compileProtoFiles = store.getBoolean(COMPILE_PROTO_FILES);
-    btnCompileProtoFiles.setSelection(compileProtoFiles);
-    btnUseProtocInSystemPath.setSelection(store.getBoolean(USE_PROTOC_IN_SYSTEM_PATH));
-    btnUseProtocInCustomPath.setSelection(store.getBoolean(USE_PROTOC_IN_CUSTOM_PATH));
-    txtProtocFilePath.setText(store.getString(PROTOC_FILE_PATH));
-    btnRefreshResources.setSelection(store.getBoolean(REFRESH_RESOURCES));
-    btnRefreshProject.setSelection(store.getBoolean(REFRESH_PROJECT));
-    btnRefreshOutputFolder.setSelection(store.getBoolean(REFRESH_OUTPUT_DIRECTORY));
-    codeGenerationEditor.codeGenerationOptions(codeGenerationPreferencesProvider.getPreferences(store));
-    boolean shouldEnableCompilerOptions = compileProtoFiles;
-    if (isPropertyPage()) {
-      boolean useProjectSettings = store.getBoolean(ENABLE_PROJECT_SETTINGS);
-      activateProjectSettings(useProjectSettings);
-      enableProjectSpecificOptions(useProjectSettings);
-      shouldEnableCompilerOptions = shouldEnableCompilerOptions && useProjectSettings;
-    }
-    enableCompilerOptions(shouldEnableCompilerOptions);
   }
 
   private void addEventListeners() {
@@ -191,7 +166,7 @@
 
   private void checkState() {
     boolean atLeastOneEnabled = false;
-    for (CodeGeneration option : codeGenerationEditor.codeGenerationOptions()) {
+    for (CodeGenerationSetting option : codeGenerationEditor.codeGenerationOptions()) {
       if (option.isEnabled()) {
         atLeastOneEnabled = true;
         break;
@@ -218,26 +193,43 @@
     pageIsNowValid();
   }
 
-  /** {@inheritDoc} */
-  @Override protected void performDefaults(IPreferenceStore store) {
-    boolean compileProtoFiles = store.getDefaultBoolean(COMPILE_PROTO_FILES);
-    btnCompileProtoFiles.setSelection(compileProtoFiles);
-    btnUseProtocInSystemPath.setSelection(store.getDefaultBoolean(USE_PROTOC_IN_SYSTEM_PATH));
-    btnUseProtocInCustomPath.setSelection(store.getDefaultBoolean(USE_PROTOC_IN_CUSTOM_PATH));
-    txtProtocFilePath.setText(store.getDefaultString(PROTOC_FILE_PATH));
-    btnRefreshResources.setSelection(store.getDefaultBoolean(REFRESH_RESOURCES));
-    btnRefreshProject.setSelection(store.getDefaultBoolean(REFRESH_PROJECT));
-    btnRefreshOutputFolder.setSelection(store.getDefaultBoolean(REFRESH_OUTPUT_DIRECTORY));
-    codeGenerationEditor.codeGenerationOptions(codeGenerationPreferencesProvider.getDefaults(store));
-    boolean enableCompilerOptions = compileProtoFiles;
+  @Override protected void setupBinding(PreferenceBinder preferenceBinder) {
+    RawPreferences preferences = new RawPreferences(getPreferenceStore());
+    preferenceBinder.addAll(
+        bindSelectionOf(btnCompileProtoFiles).to(preferences.compileProtoFiles()),
+        bindSelectionOf(btnUseProtocInSystemPath).to(preferences.useProtocInSystemPath()),
+        bindSelectionOf(btnUseProtocInCustomPath).to(preferences.useProtocInCustomPath()),
+        bindTextOf(txtProtocFilePath).to(preferences.protocPath()),
+        bindSelectionOf(btnRefreshResources).to(preferences.refreshResources()),
+        bindSelectionOf(btnRefreshProject).to(preferences.refreshProject()),
+        bindSelectionOf(btnRefreshOutputDirectory).to(preferences.refreshOutputDirectory()),
+        bindCodeGeneration(codeGenerationSettings.java())
+          .to(preferences.javaCodeGenerationEnabled(), preferences.javaOutputDirectory()),
+        bindCodeGeneration(codeGenerationSettings.cpp())
+          .to(preferences.cppCodeGenerationEnabled(), preferences.cppOutputDirectory()),
+        bindCodeGeneration(codeGenerationSettings.python())
+          .to(preferences.pythonCodeGenerationEnabled(), preferences.pythonOutputDirectory())
+      );
     if (isPropertyPage()) {
-      boolean useProjectSettings = store.getDefaultBoolean(ENABLE_PROJECT_SETTINGS);
+      preferenceBinder.add(bindSelectionOf(btnEnableProjectSettings).to(preferences.enableProjectSettings()));
+    }
+  }
+
+  @Override protected void onPageCreation() {
+    defaultsPerformed();
+  }
+
+  @Override protected void defaultsPerformed() {
+    boolean compileProtoFiles = btnCompileProtoFiles.getSelection();
+    boolean shouldEnableCompilerOptions = compileProtoFiles;
+    if (isPropertyPage()) {
+      boolean useProjectSettings = btnEnableProjectSettings.isEnabled();
       activateProjectSettings(useProjectSettings);
       enableProjectSpecificOptions(useProjectSettings);
-      enableCompilerOptions = enableCompilerOptions && useProjectSettings;
+      shouldEnableCompilerOptions = shouldEnableCompilerOptions && useProjectSettings;
     }
-    enableCompilerOptions(enableCompilerOptions);
-    super.performDefaults();
+    enableCompilerOptions(shouldEnableCompilerOptions);
+    codeGenerationEditor.codeGenerationSettings(codeGenerationSettings.allSettings());
   }
 
   /** {@inheritDoc} */
@@ -290,20 +282,7 @@
   private void refreshResourcesOptionsEnabled(boolean isEnabled) {
     grpRefresh.setEnabled(isEnabled);
     btnRefreshProject.setEnabled(isEnabled);
-    btnRefreshOutputFolder.setEnabled(isEnabled);
-  }
-
-  /** {@inheritDoc} */
-  @Override protected void savePreferences(IPreferenceStore store) {
-    if (isPropertyPage()) store.setValue(ENABLE_PROJECT_SETTINGS, areProjectSettingsActive());
-    store.setValue(COMPILE_PROTO_FILES, btnCompileProtoFiles.getSelection());
-    store.setValue(USE_PROTOC_IN_SYSTEM_PATH, btnUseProtocInSystemPath.getSelection());
-    store.setValue(USE_PROTOC_IN_CUSTOM_PATH, btnUseProtocInCustomPath.getSelection());
-    store.setValue(PROTOC_FILE_PATH, txtProtocFilePath.getText());
-    store.setValue(REFRESH_RESOURCES, btnRefreshResources.getSelection());
-    store.setValue(REFRESH_PROJECT, btnRefreshProject.getSelection());
-    store.setValue(REFRESH_OUTPUT_DIRECTORY, btnRefreshOutputFolder.getSelection());
-    codeGenerationPreferencesProvider.save(store, codeGenerationEditor.codeGenerationOptions());
+    btnRefreshOutputDirectory.setEnabled(isEnabled);
   }
 
   /** {@inheritDoc} */
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferenceStoreInitializer.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferenceStoreInitializer.java
index 6f41722..4e2b046 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferenceStoreInitializer.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferenceStoreInitializer.java
@@ -8,11 +8,8 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
 
-import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.PreferenceNames.*;
-
 import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
-import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
+import org.eclipse.xtext.ui.editor.preferences.*;
 
 /**
  * Initializes default values for the "Compiler" preferences.
@@ -26,16 +23,16 @@
   /** {@inheritDoc} */
   public void initialize(IPreferenceStoreAccess access) {
     IPreferenceStore store = access.getWritablePreferenceStore();
-    store.setDefault(ENABLE_PROJECT_SETTINGS, false);
-    store.setDefault(USE_PROTOC_IN_SYSTEM_PATH, true);
-    store.setDefault(GENERATE_JAVA_CODE, false);
-    store.setDefault(GENERATE_CPP_CODE, false);
-    store.setDefault(GENERATE_PYTHON_CODE, false);
-    store.setDefault(JAVA_OUTPUT_DIRECTORY, DEFAULT_OUTPUT_DIRECTORY);
-    store.setDefault(CPP_OUTPUT_DIRECTORY, DEFAULT_OUTPUT_DIRECTORY);
-    store.setDefault(PYTHON_OUTPUT_DIRECTORY, DEFAULT_OUTPUT_DIRECTORY);
-    store.setDefault(REFRESH_RESOURCES, true);
-    store.setDefault(REFRESH_OUTPUT_DIRECTORY, true);
+    RawPreferences preferences = new RawPreferences(store);
+    preferences.enableProjectSettings().defaultValue(false);
+    preferences.useProtocInSystemPath().defaultValue(true);
+    preferences.javaCodeGenerationEnabled().defaultValue(false);
+    preferences.cppCodeGenerationEnabled().defaultValue(false);
+    preferences.pythonCodeGenerationEnabled().defaultValue(false);
+    preferences.javaOutputDirectory().defaultValue(DEFAULT_OUTPUT_DIRECTORY);
+    preferences.cppOutputDirectory().defaultValue(DEFAULT_OUTPUT_DIRECTORY);
+    preferences.pythonOutputDirectory().defaultValue(DEFAULT_OUTPUT_DIRECTORY);
+    preferences.refreshResources().defaultValue(true);
+    preferences.refreshOutputDirectory().defaultValue(true);
   }
-
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferences.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferences.java
index 57cda26..78f8aba 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferences.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferences.java
@@ -8,10 +8,7 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
 
-import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.PreferenceNames.*;
-import static java.util.Collections.unmodifiableList;
-
-import java.util.List;
+import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.PostCompilationRefreshTarget.*;
 
 import org.eclipse.jface.preference.IPreferenceStore;
 
@@ -24,17 +21,24 @@
 
   private final boolean compileProtoFiles;
   private final String protocPath;
-  private final List<CodeGeneration> codeGenerationOptions;
+  private final CodeGenerationSettings codeGenerationSettings;
   private final boolean refreshResources;
   private final PostCompilationRefreshTarget refreshTarget;
 
-  CompilerPreferences(IPreferenceStore store, List<CodeGeneration> codeGenerationOptions) {
-    compileProtoFiles = store.getBoolean(COMPILE_PROTO_FILES);
-    boolean useProtocInSystemPath = store.getBoolean(USE_PROTOC_IN_SYSTEM_PATH);
-    protocPath = (useProtocInSystemPath) ? "protoc" : store.getString(PROTOC_FILE_PATH);
-    this.codeGenerationOptions = unmodifiableList(codeGenerationOptions);
-    refreshResources = store.getBoolean(REFRESH_RESOURCES);
-    refreshTarget = PostCompilationRefreshTarget.readFrom(store);
+  CompilerPreferences(RawPreferences preferences) {
+    compileProtoFiles = preferences.compileProtoFiles().value();
+    boolean useProtocInSystemPath = preferences.useProtocInSystemPath().value();
+    protocPath = (useProtocInSystemPath) ? "protoc" : preferences.protocPath().value();
+    codeGenerationSettings = new CodeGenerationSettings();
+    codeGenerationSettings.java().enabled(preferences.javaCodeGenerationEnabled().value());
+    codeGenerationSettings.java().outputDirectory(preferences.javaOutputDirectory().value());
+    codeGenerationSettings.cpp().enabled(preferences.cppCodeGenerationEnabled().value());
+    codeGenerationSettings.cpp().outputDirectory(preferences.cppOutputDirectory().value());
+    codeGenerationSettings.python().enabled(preferences.pythonCodeGenerationEnabled().value());
+    codeGenerationSettings.python().outputDirectory(preferences.pythonOutputDirectory().value());
+    refreshResources = preferences.refreshResources().value();
+    boolean refreshProject = preferences.refreshProject().value();
+    refreshTarget = refreshProject ? PROJECT : OUTPUT_DIRECTORIES;
   }
 
   public boolean shouldCompileProtoFiles() {
@@ -45,8 +49,8 @@
     return protocPath;
   }
 
-  public List<CodeGeneration> codeGenerationOptions() {
-    return codeGenerationOptions;
+  public CodeGenerationSettings codeGenerationSettings() {
+    return codeGenerationSettings;
   }
 
   public boolean shouldRefreshResources() {
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencesProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencesProvider.java
index 531ca77..658fc05 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencesProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/CompilerPreferencesProvider.java
@@ -8,8 +8,6 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
 
-import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.PreferenceNames.ENABLE_PROJECT_SETTINGS;
-
 import org.eclipse.core.resources.IProject;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
@@ -24,12 +22,12 @@
 public class CompilerPreferencesProvider {
 
   @Inject private IPreferenceStoreAccess storeAccess;
-  @Inject private CodeGenerationPreferencesProvider codeGenerationPreferencesProvider;
 
   public CompilerPreferences getPreferences(IProject project) {
     IPreferenceStore store = storeAccess.getWritablePreferenceStore(project);
-    boolean useProjectPreferences = store.getBoolean(ENABLE_PROJECT_SETTINGS);
+    RawPreferences preferences = new RawPreferences(store);
+    boolean useProjectPreferences = preferences.enableProjectSettings().value();
     if (!useProjectPreferences) store = storeAccess.getWritablePreferenceStore();
-    return new CompilerPreferences(store, codeGenerationPreferencesProvider.getPreferences(store));
+    return new CompilerPreferences(new RawPreferences(store));
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/EditCodeGenerationDialog.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/EditCodeGenerationDialog.java
index 59fe93c..2db3b2a 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/EditCodeGenerationDialog.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/EditCodeGenerationDialog.java
@@ -30,7 +30,7 @@
  */
 public class EditCodeGenerationDialog extends InputDialog {
 
-  private final CodeGeneration option;
+  private final CodeGenerationSetting option;
 
   private Text txtOutputDirectory;
   private Button btnEnabled;
@@ -41,7 +41,7 @@
    * @param parent a shell which will be the parent of the new instance.
    * @param option the code generation option to edit.
    */
-  public EditCodeGenerationDialog(Shell parent, CodeGeneration option) {
+  public EditCodeGenerationDialog(Shell parent, CodeGenerationSetting option) {
     super(parent, editCodeGenerationOptionTitle + option.language().name());
     this.option = option;
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/PostCompilationRefreshTarget.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/PostCompilationRefreshTarget.java
index ba7a750..2fb2cbf 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/PostCompilationRefreshTarget.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/PostCompilationRefreshTarget.java
@@ -8,10 +8,6 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
 
-import static com.google.eclipse.protobuf.ui.preferences.pages.compiler.PreferenceNames.REFRESH_PROJECT;
-
-import org.eclipse.jface.preference.IPreferenceStore;
-
 /**
  * The type of resource to refresh after calling protoc.
  *
@@ -21,8 +17,4 @@
 
   PROJECT, OUTPUT_DIRECTORIES;
 
-  static PostCompilationRefreshTarget readFrom(IPreferenceStore store) {
-    if (store.getBoolean(REFRESH_PROJECT)) return PROJECT;
-    return OUTPUT_DIRECTORIES;
-  }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/PreferenceNames.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/PreferenceNames.java
deleted file mode 100644
index 0157080..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/PreferenceNames.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-final class PreferenceNames {
-
-  static final String ENABLE_PROJECT_SETTINGS = "compiler.enableProjectSettings";
-  static final String COMPILE_PROTO_FILES = "compiler.compileProtoFiles";
-  static final String USE_PROTOC_IN_SYSTEM_PATH = "compiler.useProtocInSystemPath";
-  static final String USE_PROTOC_IN_CUSTOM_PATH = "compiler.useProtocInCustomPath";
-  static final String PROTOC_FILE_PATH = "compiler.protocFilePath";
-  static final String GENERATE_JAVA_CODE = "compiler.javaCodeGenerationEnabled";
-  static final String GENERATE_CPP_CODE = "compiler.cppCodeGenerationEnabled";
-  static final String GENERATE_PYTHON_CODE = "compiler.pythonCodeGenerationEnabled";
-  static final String JAVA_OUTPUT_DIRECTORY = "compiler.javaOutputDirectory";
-  static final String CPP_OUTPUT_DIRECTORY = "compiler.cppOutputDirectory";
-  static final String PYTHON_OUTPUT_DIRECTORY = "compiler.pythonOutputDirectory";
-  static final String REFRESH_RESOURCES = "compiler.refreshResources";
-  static final String REFRESH_PROJECT = "compiler.refreshProject";
-  static final String REFRESH_OUTPUT_DIRECTORY = "compiler.refreshOutputDirectory";
-
-  private PreferenceNames() {}
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/RawPreferences.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/RawPreferences.java
new file mode 100644
index 0000000..1394d3b
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/compiler/RawPreferences.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences.pages.compiler;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import com.google.eclipse.protobuf.ui.preferences.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class RawPreferences {
+
+  private final BooleanPreference enableProjectSettings;
+  private final BooleanPreference compileProtoFiles;
+  private final BooleanPreference useProtocInSystemPath;
+  private final BooleanPreference useProtocInCustomPath;
+  private final StringPreference protocPath;
+  private final BooleanPreference javaCodeGenerationEnabled;
+  private final BooleanPreference cppCodeGenerationEnabled;
+  private final BooleanPreference pythonCodeGenerationEnabled;
+  private final StringPreference javaOutputDirectory;
+  private final StringPreference cppOutputDirectory;
+  private final StringPreference pythonOutputDirectory;
+  private final BooleanPreference refreshResources;
+  private final BooleanPreference refreshProject;
+  private final BooleanPreference refreshOutputDirectory;
+
+  RawPreferences(IPreferenceStore store) {
+    enableProjectSettings = new BooleanPreference("compiler.enableProjectSettings", store);
+    compileProtoFiles = new BooleanPreference("compiler.compileProtoFiles", store);
+    useProtocInSystemPath = new BooleanPreference("compiler.useProtocInSystemPath", store);
+    useProtocInCustomPath = new BooleanPreference("compiler.useProtocInCustomPath", store);
+    protocPath = new StringPreference("compiler.protocFilePath", store);
+    javaCodeGenerationEnabled = new BooleanPreference("compiler.javaCodeGenerationEnabled", store);
+    cppCodeGenerationEnabled = new BooleanPreference("compiler.cppCodeGenerationEnabled", store);
+    pythonCodeGenerationEnabled = new BooleanPreference("compiler.pythonCodeGenerationEnabled", store);
+    javaOutputDirectory = new StringPreference("compiler.javaOutputDirectory", store);
+    cppOutputDirectory = new StringPreference("compiler.cppOutputDirectory", store);
+    pythonOutputDirectory = new StringPreference("compiler.pythonOutputDirectory", store);
+    refreshResources = new BooleanPreference("compiler.refreshResources", store);
+    refreshProject = new BooleanPreference("compiler.refreshProject", store);
+    refreshOutputDirectory = new BooleanPreference("compiler.refreshOutputDirectory", store);
+  }
+
+  BooleanPreference enableProjectSettings() {
+    return enableProjectSettings;
+  }
+
+  BooleanPreference compileProtoFiles() {
+    return compileProtoFiles;
+  }
+
+  BooleanPreference useProtocInSystemPath() {
+    return useProtocInSystemPath;
+  }
+
+  BooleanPreference useProtocInCustomPath() {
+    return useProtocInCustomPath;
+  }
+
+  StringPreference protocPath() {
+    return protocPath;
+  }
+
+  BooleanPreference javaCodeGenerationEnabled() {
+    return javaCodeGenerationEnabled;
+  }
+
+  BooleanPreference cppCodeGenerationEnabled() {
+    return cppCodeGenerationEnabled;
+  }
+
+  BooleanPreference pythonCodeGenerationEnabled() {
+    return pythonCodeGenerationEnabled;
+  }
+
+  StringPreference javaOutputDirectory() {
+    return javaOutputDirectory;
+  }
+
+  StringPreference cppOutputDirectory() {
+    return cppOutputDirectory;
+  }
+
+  StringPreference pythonOutputDirectory() {
+    return pythonOutputDirectory;
+  }
+
+  BooleanPreference refreshResources() {
+    return refreshResources;
+  }
+
+  BooleanPreference refreshProject() {
+    return refreshProject;
+  }
+
+  BooleanPreference refreshOutputDirectory() {
+    return refreshOutputDirectory;
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/general/GeneralSettingsPreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/general/GeneralSettingsPreferencePage.java
index 40066aa..ef637d1 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/general/GeneralSettingsPreferencePage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/general/GeneralSettingsPreferencePage.java
@@ -8,51 +8,40 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.general;
 
-import com.google.eclipse.protobuf.ui.preferences.pages.PreferenceAndPropertyPage;
-
-import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.*;
 import org.eclipse.swt.widgets.*;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
+
+import com.google.eclipse.protobuf.ui.preferences.binding.PreferenceBinder;
+import com.google.eclipse.protobuf.ui.preferences.pages.PreferenceAndPropertyPage;
 
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class GeneralSettingsPreferencePage extends PreferenceAndPropertyPage {
-  public GeneralSettingsPreferencePage() {
-  }
 
   private static final String PREFERENCE_PAGE_ID = GeneralSettingsPreferencePage.class.getName();
-  
+
   /** {@inheritDoc} */
-  @Override protected Control createContents(Composite parent) {
+  @Override protected void doCreateContents(Composite contents) {
     // generated by WindowBuilder
-    Composite contents = super.switchBetweenProjectAndWorkspaceSettings(parent);
-    GridLayout gridLayout = (GridLayout) contents.getLayout();
-    gridLayout.numColumns = 2;
-   
     Group grpValidation = new Group(contents, SWT.NONE);
     grpValidation.setLayout(new GridLayout(1, false));
-    grpValidation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+    grpValidation.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
     grpValidation.setText("Content Validation");
-    
+
     Button btnValidateOnActivation = new Button(grpValidation, SWT.CHECK);
     btnValidateOnActivation.setText("Validate files when activated");
-    return contents;
   }
 
   /** {@inheritDoc} */
+  @Override protected void setupBinding(PreferenceBinder preferenceBinder) {}
+
+  /** {@inheritDoc} */
   @Override protected void onProjectSettingsActivation(boolean active) {}
 
   /** {@inheritDoc} */
   @Override protected String preferencePageId() {
     return PREFERENCE_PAGE_ID;
   }
-
-  /** {@inheritDoc} */
-  @Override protected void savePreferences(IPreferenceStore store) {}
-
-  /** {@inheritDoc} */
-  @Override protected void performDefaults(IPreferenceStore store) {}
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathResolutionType.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathResolutionType.java
index bb8e24c..29fbfa6 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathResolutionType.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathResolutionType.java
@@ -5,23 +5,16 @@
  * Public License v1.0 which accompanies this distribution, and is available at
  *
  * http://www.eclipse.org/legal/epl-v10.html
- */package com.google.eclipse.protobuf.ui.preferences.pages.paths;
-
-import static com.google.eclipse.protobuf.ui.preferences.pages.paths.PreferenceNames.FILES_IN_ONE_DIRECTORY_ONLY;
-
-import org.eclipse.jface.preference.IPreferenceStore;
+ */
+package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
 /**
  * Types of file resolution.
- * 
+ *
  * @author alruiz@google.com (Alex Ruiz)
  */
 public enum PathResolutionType {
 
   SINGLE_DIRECTORY, MULTIPLE_DIRECTORIES;
-  
-  static PathResolutionType readFrom(IPreferenceStore store) {
-    if (store.getBoolean(FILES_IN_ONE_DIRECTORY_ONLY)) return SINGLE_DIRECTORY;
-    return MULTIPLE_DIRECTORIES;
-  }
+
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencePage.java
index 64e0e5c..925bcb2 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencePage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencePage.java
@@ -8,8 +8,8 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
+import static com.google.eclipse.protobuf.ui.preferences.binding.BindingToButtonSelection.bindSelectionOf;
 import static com.google.eclipse.protobuf.ui.preferences.pages.paths.Messages.*;
-import static com.google.eclipse.protobuf.ui.preferences.pages.paths.PreferenceNames.*;
 import static com.google.eclipse.protobuf.ui.swt.EventListeners.addSelectionListener;
 import static java.util.Arrays.asList;
 import static java.util.Collections.unmodifiableList;
@@ -18,7 +18,6 @@
 import java.util.*;
 import java.util.List;
 
-import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.*;
 import org.eclipse.swt.layout.*;
@@ -47,15 +46,15 @@
 
   @Inject private PluginImageHelper imageHelper;
 
-  private final PreferenceBinder preferenceBinder = new PreferenceBinder();
-
-  /** {@inheritDoc} */
-  @Override protected Control createContents(Composite parent) {
-    // generated by WindowBuilder
-    Composite contents = new Composite(parent, NONE);
+  @Override protected Composite contentParent(Composite parent) {
+    Composite contents = new Composite(parent, SWT.NONE);
     contents.setLayout(new GridLayout(3, false));
+    return contents;
+  }
 
-    grpResolutionOfImported = new Group(contents, SWT.NONE);
+  @Override protected void doCreateContents(Composite parent) {
+    // generated by WindowBuilder
+    grpResolutionOfImported = new Group(parent, SWT.NONE);
     grpResolutionOfImported.setLayout(new GridLayout(1, false));
     grpResolutionOfImported.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
     grpResolutionOfImported.setText(importedFilesPathResolution);
@@ -70,55 +69,9 @@
 
     directoryPathsEditor = new DirectoryPathsEditor(grpResolutionOfImported, project(), imageHelper);
     directoryPathsEditor.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
-    new Label(contents, SWT.NONE);
+    new Label(parent, SWT.NONE);
 
-    setUpBinding();
-    updateFromPreferenceStore();
     addEventListeners();
-
-    return contents;
-  }
-
-  private void setUpBinding() {
-    preferenceBinder.bind(FILES_IN_ONE_DIRECTORY_ONLY, btnOneDirectoryOnly);
-    preferenceBinder.bind(FILES_IN_MULTIPLE_DIRECTORIES, btnMultipleDirectories);
-    preferenceBinder.add(new Binding() {
-      public void read(IPreferenceStore store) {
-        setDirectoryPaths(store.getString(IMPORT_ROOTS));
-      }
-
-      public void readDefault(IPreferenceStore store) {
-        setDirectoryPaths(store.getDefaultString(IMPORT_ROOTS));
-      }
-
-      public void save(IPreferenceStore store) {
-        store.setValue(IMPORT_ROOTS, directoryNames());
-      }
-    });
-  }
-
-  private String directoryNames() {
-    List<DirectoryPath> paths = directoryPathsEditor.directoryPaths();
-    if (paths.isEmpty()) return "";
-    List<String> pathsAsText = new ArrayList<String>();
-    for (DirectoryPath path : paths) {
-      pathsAsText.add(path.toString());
-    }
-    return concat(COMMA_DELIMITER, pathsAsText);
-  }
-
-  private void setDirectoryPaths(String directoryPaths) {
-    List<DirectoryPath> paths = new ArrayList<DirectoryPath>();
-    for (String path : split(directoryPaths, COMMA_DELIMITER)) {
-      if (isEmpty(path)) continue;
-      paths.add(DirectoryPath.parse(path));
-    }
-    directoryPathsEditor.directoryPaths(unmodifiableList(paths));
-  }
-
-  private void updateFromPreferenceStore() {
-    preferenceBinder.readPreferences(getPreferenceStore());
-    enableProjectOptions(true);
   }
 
   private void addEventListeners() {
@@ -144,15 +97,58 @@
     pageIsNowValid();
   }
 
+  @Override protected void setupBinding(PreferenceBinder preferenceBinder) {
+    RawPreferences preferences = new RawPreferences(getPreferenceStore());
+    preferenceBinder.addAll(
+        bindSelectionOf(btnOneDirectoryOnly).to(preferences.filesInOneDirectoryOnly()),
+        bindSelectionOf(btnMultipleDirectories).to(preferences.filesInMultipleDirectories())
+      );
+    final StringPreference directoryPaths = preferences.directoryPaths();
+    preferenceBinder.add(new Binding() {
+      public void applyPreferenceValueToTarget() {
+        setDirectoryPaths(directoryPaths.value());
+      }
+
+      public void applyDefaultPreferenceValueToTarget() {
+        setDirectoryPaths(directoryPaths.defaultValue());
+      }
+
+      public void savePreferenceValue() {
+        directoryPaths.value(directoryNames());
+      }
+    });
+  }
+
+  private String directoryNames() {
+    List<DirectoryPath> paths = directoryPathsEditor.directoryPaths();
+    if (paths.isEmpty()) return "";
+    List<String> pathsAsText = new ArrayList<String>();
+    for (DirectoryPath path : paths) {
+      pathsAsText.add(path.toString());
+    }
+    return concat(COMMA_DELIMITER, pathsAsText);
+  }
+
+  private void setDirectoryPaths(String directoryPaths) {
+    List<DirectoryPath> paths = new ArrayList<DirectoryPath>();
+    for (String path : split(directoryPaths, COMMA_DELIMITER)) {
+      if (isEmpty(path)) continue;
+      paths.add(DirectoryPath.parse(path));
+    }
+    directoryPathsEditor.directoryPaths(unmodifiableList(paths));
+  }
+
+  @Override protected void onPageCreation() {
+    defaultsPerformed();
+  }
+
   /** {@inheritDoc} */
   @Override protected void onProjectSettingsActivation(boolean active) {
     enableProjectOptions(active);
   }
 
-  @Override protected void performDefaults(IPreferenceStore store) {
-    preferenceBinder.readDefaultPreferences(store);
+  @Override protected void defaultsPerformed() {
     enableProjectOptions(true);
-    super.performDefaults();
   }
 
   private void enableProjectOptions(boolean enabled) {
@@ -163,11 +159,6 @@
   }
 
   /** {@inheritDoc} */
-  @Override protected void savePreferences(IPreferenceStore store) {
-    preferenceBinder.savePreferences(store);
-  }
-
-  /** {@inheritDoc} */
   @Override protected String preferencePageId() {
     return PREFERENCE_PAGE_ID;
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferenceStoreInitializer.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferenceStoreInitializer.java
index 794538f..b5e8876 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferenceStoreInitializer.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferenceStoreInitializer.java
@@ -8,11 +8,8 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
-import static com.google.eclipse.protobuf.ui.preferences.pages.paths.PreferenceNames.*;
-
 import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
-import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
+import org.eclipse.xtext.ui.editor.preferences.*;
 
 /**
  * Initializes default values for the "Paths" preferences.
@@ -24,9 +21,9 @@
   /** {@inheritDoc} */
   public void initialize(IPreferenceStoreAccess access) {
     IPreferenceStore store = access.getWritablePreferenceStore();
-    store.setDefault(FILES_IN_ONE_DIRECTORY_ONLY, true);
-    store.setDefault(FILES_IN_MULTIPLE_DIRECTORIES, false);
-    store.setDefault(IMPORT_ROOTS, "");
+    RawPreferences preferences = new RawPreferences(store);
+    preferences.filesInOneDirectoryOnly().defaultValue(true);
+    preferences.filesInMultipleDirectories().defaultValue(false);
+    preferences.directoryPaths().defaultValue("");
   }
-
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferences.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferences.java
index dab2d73..cf5b6e0 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferences.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferences.java
@@ -8,19 +8,18 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.pages.paths;
 
-import static com.google.eclipse.protobuf.ui.preferences.pages.paths.PathResolutionType.SINGLE_DIRECTORY;
-import static com.google.eclipse.protobuf.ui.preferences.pages.paths.PreferenceNames.IMPORT_ROOTS;
+import static com.google.eclipse.protobuf.ui.preferences.pages.paths.PathResolutionType.*;
 import static com.google.eclipse.protobuf.ui.util.Strings.CSV_PATTERN;
 import static java.util.Collections.*;
 
+import java.util.*;
+
 import org.eclipse.core.resources.IProject;
 import org.eclipse.jface.preference.IPreferenceStore;
 
-import java.util.*;
-
 /**
  * Paths preferences, retrieved from an <code>{@link IPreferenceStore}</code>. To create a new instance invoke
- * <code>{@link PathsPreferencesProvider#getPreferences(org.eclipse.core.resources.IProject)}</code>
+ * <code>{@link PathsPreferencesFactory#preferences(IProject)}</code>
  *
  * @author alruiz@google.com (Alex Ruiz)
  */
@@ -29,15 +28,16 @@
   private final PathResolutionType pathResolutionType;
   private final List<DirectoryPath> importRoots;
 
-  PathsPreferences(IPreferenceStore store, IProject project) {
-    pathResolutionType = PathResolutionType.readFrom(store);
-    importRoots = importRoots(pathResolutionType, store, project);
+  PathsPreferences(RawPreferences preferences, IProject project) {
+    boolean filesInOneDirectoryOnly = preferences.filesInOneDirectoryOnly().value();
+    pathResolutionType = filesInOneDirectoryOnly ? SINGLE_DIRECTORY : MULTIPLE_DIRECTORIES;
+    importRoots = importRoots(preferences, project);
   }
 
-  private static List<DirectoryPath> importRoots(PathResolutionType resolutionType, IPreferenceStore store, IProject project) {
-    if (resolutionType.equals(SINGLE_DIRECTORY)) return emptyList();
+  private List<DirectoryPath> importRoots(RawPreferences preferences, IProject project) {
+    if (pathResolutionType.equals(SINGLE_DIRECTORY)) return emptyList();
     List<DirectoryPath> roots = new ArrayList<DirectoryPath>();
-    for (String root : store.getString(IMPORT_ROOTS).split(CSV_PATTERN)) {
+    for (String root : preferences.directoryPaths().value().split(CSV_PATTERN)) {
       roots.add(DirectoryPath.parse(root, project));
     }
     return unmodifiableList(roots);
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencesProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencesFactory.java
similarity index 76%
rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencesProvider.java
rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencesFactory.java
index 0f11255..8b48810 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencesProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PathsPreferencesFactory.java
@@ -15,16 +15,17 @@
 import com.google.inject.Inject;
 
 /**
- * Reads "paths" preferences.
- * 
+ * Factory of <code>{@link PathsPreferences}</code>.
+ *
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class PathsPreferencesProvider {
+
+public class PathsPreferencesFactory {
 
   @Inject private IPreferenceStoreAccess storeAccess;
-  
-  public PathsPreferences getPreferences(IProject project) {
+
+  public PathsPreferences preferences(IProject project) {
     IPreferenceStore store = storeAccess.getWritablePreferenceStore(project);
-    return new PathsPreferences(store, project);
+    return new PathsPreferences(new RawPreferences(store), project);
   }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PreferenceNames.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PreferenceNames.java
deleted file mode 100644
index c76d17d..0000000
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/PreferenceNames.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2011 Google Inc.
- *
- * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
- * Public License v1.0 which accompanies this distribution, and is available at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.google.eclipse.protobuf.ui.preferences.pages.paths;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-final class PreferenceNames {
-
-  static final String FILES_IN_ONE_DIRECTORY_ONLY = "paths.filesInOneDirectoryOnly";
-  static final String FILES_IN_MULTIPLE_DIRECTORIES = "paths.filesInMultipleDirectories";
-  static final String IMPORT_ROOTS = "paths.directoryPaths";
-
-  private PreferenceNames() {}
-}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/RawPreferences.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/RawPreferences.java
new file mode 100644
index 0000000..c1f77f7
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/pages/paths/RawPreferences.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.preferences.pages.paths;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import com.google.eclipse.protobuf.ui.preferences.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class RawPreferences {
+
+  private final BooleanPreference filesInOneDirectoryOnly;
+  private final BooleanPreference filesInMultipleDirectories;
+  private final StringPreference directoryPaths;
+
+  RawPreferences(IPreferenceStore store) {
+    filesInOneDirectoryOnly = new BooleanPreference("paths.filesInOneDirectoryOnly", store);
+    filesInMultipleDirectories = new BooleanPreference("paths.filesInMultipleDirectories", store);
+    directoryPaths = new StringPreference("paths.directoryPaths", store);
+  }
+
+  BooleanPreference filesInOneDirectoryOnly() {
+    return filesInOneDirectoryOnly;
+  }
+
+  BooleanPreference filesInMultipleDirectories() {
+    return filesInMultipleDirectories;
+  }
+
+  StringPreference directoryPaths() {
+    return directoryPaths;
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
index dffb88c..c509ea5 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver.java
@@ -26,7 +26,7 @@
  */
 public class FileUriResolver implements IFileUriResolver {
 
-  @Inject private PathsPreferencesProvider preferenceProvider;
+  @Inject private PathsPreferencesFactory preferencesFactory;
   @Inject private FileResolverStrategies resolvers;
   @Inject private Resources resources;
 
@@ -60,7 +60,7 @@
     IProject project = resources.project(resourceUri);
     if (project == null) project = resources.activeProject();
     if (project == null) throw new IllegalStateException("Unable to find current project");
-    PathsPreferences preferences = preferenceProvider.getPreferences(project);
+    PathsPreferences preferences = preferencesFactory.preferences(project);
     return resolver(preferences).resolveUri(importUri, resourceUri, preferences);
   }