In progress: [ Issue 40 ] Add support for import resolution across multiple folders
https://code.google.com/p/protobuf-dt/issues/detail?id=40

Adding a preference page for import paths.
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
index 130f949..8a14bb3 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -8,6 +8,8 @@
  */
 package com.google.eclipse.protobuf.ui;
 
+import static com.google.inject.name.Names.named;
+
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
 import org.eclipse.xtext.ui.editor.IXtextEditorCallback;
@@ -18,8 +20,8 @@
 import com.google.eclipse.protobuf.ui.outline.LinkWithEditor;
 import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage;
 import com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferencesInitializer;
+import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferencesInitializer;
 import com.google.inject.Binder;
-import com.google.inject.name.Names;
 
 /**
  * Use this class to register components to be used within the IDE.
@@ -48,9 +50,15 @@
   }
 
   public void configureCompilerPreferencesInitializer(Binder binder) {
-    binder.bind(IPreferenceStoreInitializer.class)
-          .annotatedWith(Names.named("compilerPreferences"))
-          .to(CompilerPreferencesInitializer.class);
+    configurePreferenceInitializer(binder, "compilerPreferences", CompilerPreferencesInitializer.class);
   }
 
+  public void configurePathsPreferencesInitializer(Binder binder) {
+    configurePreferenceInitializer(binder, "pathsPreferences", PathsPreferencesInitializer.class);
+  }
+  
+  private void configurePreferenceInitializer(Binder binder, String name,
+      Class<? extends IPreferenceStoreInitializer> initializerType) {
+    binder.bind(IPreferenceStoreInitializer.class).annotatedWith(named(name)).to(initializerType);
+  }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/PreferenceAndPropertyPage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/PreferenceAndPropertyPage.java
index 0891d2e..6625380 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/PreferenceAndPropertyPage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/PreferenceAndPropertyPage.java
@@ -18,8 +18,7 @@
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.PreferencePage;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.*;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.*;
@@ -185,4 +184,40 @@
    * Saves the current settings.
    */
   protected abstract void savePreferences();
+  
+  /**
+   * Adds the given <code>{@link SelectionListener}</code> to the given <code>{@link Button}</code>s.
+   * @param listener the listener to add.
+   * @param buttons the buttons to add the listener to.
+   */
+  protected static void addSelectionListener(SelectionListener listener, Button...buttons) {
+    for (Button button : buttons) button.addSelectionListener(listener);
+  }
+  
+  /**
+   * Adds the given <code>{@link ModifyListener}</code> to the given <code>{@link Text}</code> widgets.
+   * @param listener the listener to add.
+   * @param texts the text widgets to add the listener to.
+   */
+  protected static void addModifyListener(ModifyListener listener, Text...texts) {
+    for (Text text : texts) text.addModifyListener(listener);
+  }
+
+  /**
+   * Marks this page as "valid."
+   */
+  protected final void pageIsNowValid() {
+    setErrorMessage(null);
+    setValid(true);
+  }
+
+  /**
+   * Marks this page as "invalid."
+   * @param errorMessage the error message to display.
+   */
+  protected final void pageIsNowInvalid(String errorMessage) {
+    setErrorMessage(errorMessage);
+    setValid(false);
+  }
 }
+
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PreferencePage.java
index 2b1326b..6dedd47 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PreferencePage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/PreferencePage.java
@@ -10,13 +10,11 @@
 
 import static com.google.eclipse.protobuf.ui.preferences.compiler.Messages.*;
 import static com.google.eclipse.protobuf.ui.preferences.compiler.PreferenceNames.*;
-import static org.eclipse.core.resources.IResource.FOLDER;
 import static org.eclipse.core.runtime.IStatus.OK;
+import static org.eclipse.xtext.util.Strings.isEmpty;
 
 import java.io.File;
 
-import org.eclipse.core.resources.IWorkspace;
-import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.swt.SWT;
@@ -27,6 +25,7 @@
 import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
 
 import com.google.eclipse.protobuf.ui.preferences.PreferenceAndPropertyPage;
+import com.google.eclipse.protobuf.ui.util.FolderNameValidator;
 import com.google.inject.Inject;
 
 /**
@@ -60,6 +59,8 @@
   private Button btnRefreshOutputFolder;
   private Label lblOutputFolderRelative;
 
+  @Inject private FolderNameValidator folderNameValidator;
+  
   @Inject public PreferencePage(IPreferenceStoreAccess preferenceStoreAccess) {
     super(preferenceStoreAccess);
   }
@@ -180,38 +181,31 @@
     btnRefreshResources.setSelection(store.getBoolean(REFRESH_RESOURCES));
     btnRefreshProject.setSelection(store.getBoolean(REFRESH_PROJECT));
     btnRefreshOutputFolder.setSelection(store.getBoolean(REFRESH_OUTPUT_FOLDER));
-    boolean enableCompilerOptions = compileProtoFiles;
+    boolean shouldEnableCompilerOptions = compileProtoFiles;
     if (isPropertyPage()) {
       boolean useProjectSettings = store.getBoolean(ENABLE_PROJECT_SETTINGS);
       activateProjectSettings(useProjectSettings);
-      setProjectSpecificOptionsEnabled(useProjectSettings);
-      enableCompilerOptions = enableCompilerOptions && useProjectSettings;
+      enableProjectSpecificOptions(useProjectSettings);
+      shouldEnableCompilerOptions = shouldEnableCompilerOptions && useProjectSettings;
     }
-    setCompilerOptionsEnabled(enableCompilerOptions);
+    enableCompilerOptions(shouldEnableCompilerOptions);
   }
 
   private void addEventListeners() {
     btnCompileProtoFiles.addSelectionListener(new SelectionAdapter() {
       @Override public void widgetSelected(SelectionEvent e) {
         boolean selected = btnCompileProtoFiles.getSelection();
-        setCompilerOptionsEnabled(selected);
+        enableCompilerOptions(selected);
         checkState();
       }
     });
-    btnUseProtocInSystemPath.addSelectionListener(new SelectionAdapter() {
+    addSelectionListener(new SelectionAdapter() {
       @Override public void widgetSelected(SelectionEvent e) {
-        boolean selected = btnCompileProtoFiles.getSelection();
-        setCompilerCustomPathOptionsEnabled(!selected);
+        boolean selected = btnUseProtocInCustomPath.getSelection();
+        enableCompilerCustomPathOptions(!selected);
         checkState();
       }
-    });
-    btnUseProtocInCustomPath.addSelectionListener(new SelectionAdapter() {
-      @Override public void widgetSelected(SelectionEvent e) {
-        boolean selected = btnCompileProtoFiles.getSelection();
-        setCompilerCustomPathOptionsEnabled(selected);
-        checkState();
-      }
-    });
+    }, btnUseProtocInCustomPath, btnUseProtocInSystemPath);
     btnProtocPathBrowse.addSelectionListener(new SelectionAdapter() {
       @Override public void widgetSelected(SelectionEvent e) {
         FileDialog dialog = new FileDialog(getShell(), SWT.OPEN | SWT.SHEET);
@@ -224,23 +218,20 @@
         refreshResourcesOptionsEnabled(btnRefreshResources.getSelection());
       }
     });
-    ModifyListener modifyListener = new ModifyListener() {
+    addModifyListener(new ModifyListener() {
       public void modifyText(ModifyEvent e) {
         checkState();
       }
-    };
-    txtProtocFilePath.addModifyListener(modifyListener);
-    txtOutputFolderName.addModifyListener(modifyListener);
+    }, txtProtocFilePath, txtOutputFolderName);
   }
 
   private void checkState() {
     String folderName = txtOutputFolderName.getText();
-    if (folderName == null || folderName.length() == 0) {
+    if (isEmpty(folderName)) {
       pageIsNowInvalid(errorNoOutputFolderName);
       return;
     }
-    IWorkspace workspace = ResourcesPlugin.getWorkspace();
-    IStatus validFolderName = workspace.validateName(folderName, FOLDER);
+    IStatus validFolderName = folderNameValidator.validateFolderName(folderName);
     if (validFolderName.getCode() != OK) {
       pageIsNowInvalid(validFolderName.getMessage());
       return;
@@ -249,12 +240,12 @@
       pageIsNowValid();
       return;
     }
-    String text = txtProtocFilePath.getText();
-    if (text == null || text.length() == 0) {
+    String protocPath = txtProtocFilePath.getText();
+    if (isEmpty(protocPath)) {
       pageIsNowInvalid(errorNoSelection);
       return;
     }
-    File file = new File(text);
+    File file = new File(protocPath);
     if (!file.isFile() || !"protoc".equals(file.getName())) {
       pageIsNowInvalid(errorInvalidProtoc);
       return;
@@ -262,16 +253,6 @@
     pageIsNowValid();
   }
 
-  private void pageIsNowValid() {
-    setErrorMessage(null);
-    setValid(true);
-  }
-
-  private void pageIsNowInvalid(String errorMessage) {
-    setErrorMessage(errorMessage);
-    setValid(false);
-  }
-
   /** {@inheritDoc} */
   @Override protected void performDefaults() {
     IPreferenceStore store = doGetPreferenceStore();
@@ -291,33 +272,39 @@
     if (isPropertyPage()) {
       boolean useProjectSettings = store.getDefaultBoolean(ENABLE_PROJECT_SETTINGS);
       activateProjectSettings(useProjectSettings);
-      setProjectSpecificOptionsEnabled(useProjectSettings);
+      enableProjectSpecificOptions(useProjectSettings);
       enableCompilerOptions = enableCompilerOptions && useProjectSettings;
     }
-    setCompilerOptionsEnabled(enableCompilerOptions);
+    enableCompilerOptions(enableCompilerOptions);
     super.performDefaults();
   }
+  
+  /** {@inheritDoc} */
+  @Override protected void onProjectSettingsActivation(boolean active) {
+    enableProjectSpecificOptions(active);
+    enableCompilerOptions(isEnabledAndSelected(btnCompileProtoFiles));
+  }
 
-  private void setProjectSpecificOptionsEnabled(boolean enabled) {
+  private void enableProjectSpecificOptions(boolean enabled) {
     btnCompileProtoFiles.setEnabled(enabled);
   }
 
-  private void setCompilerOptionsEnabled(boolean enabled) {
+  private void enableCompilerOptions(boolean enabled) {
     tabFolder.setEnabled(enabled);
-    setCompilerPathOptionsEnabled(enabled);
-    setTargetLanguageOptionsEnabled(enabled);
-    setOutputOptionsEnabled(enabled);
-    setRefreshOptionsEnabled(enabled);
+    enableCompilerPathOptions(enabled);
+    enableTargetLanguageOptions(enabled);
+    enableOutputOptions(enabled);
+    enableRefreshOptions(enabled);
   }
 
-  private void setCompilerPathOptionsEnabled(boolean enabled) {
+  private void enableCompilerPathOptions(boolean enabled) {
     grpCompilerLocation.setEnabled(enabled);
     btnUseProtocInSystemPath.setEnabled(enabled);
     btnUseProtocInCustomPath.setEnabled(enabled);
-    setCompilerCustomPathOptionsEnabled(customPathOptionSelectedAndEnabled());
+    enableCompilerCustomPathOptions(customPathOptionSelectedAndEnabled());
   }
 
-  private void setCompilerCustomPathOptionsEnabled(boolean enabled) {
+  private void enableCompilerCustomPathOptions(boolean enabled) {
     txtProtocFilePath.setEnabled(enabled);
     btnProtocPathBrowse.setEnabled(enabled);
   }
@@ -330,21 +317,21 @@
     return b.isEnabled() && b.getSelection();
   }
 
-  private void setTargetLanguageOptionsEnabled(boolean enabled) {
+  private void enableTargetLanguageOptions(boolean enabled) {
     grpTargetLanguage.setEnabled(enabled);
     btnJava.setEnabled(enabled);
     btnCpp.setEnabled(enabled);
     btnPython.setEnabled(enabled);
   }
 
-  private void setOutputOptionsEnabled(boolean enabled) {
+  private void enableOutputOptions(boolean enabled) {
     grpOutput.setEnabled(enabled);
     lblOutputFolderName.setEnabled(enabled);
     txtOutputFolderName.setEnabled(enabled);
     lblOutputFolderRelative.setEnabled(enabled);
   }
 
-  private void setRefreshOptionsEnabled(boolean enabled) {
+  private void enableRefreshOptions(boolean enabled) {
     btnRefreshResources.setEnabled(enabled);
     refreshResourcesOptionsEnabled(isEnabledAndSelected(btnRefreshResources));
   }
@@ -375,12 +362,6 @@
   }
   
   /** {@inheritDoc} */
-  @Override protected void onProjectSettingsActivation(boolean active) {
-    setProjectSpecificOptionsEnabled(active);
-    setCompilerOptionsEnabled(isEnabledAndSelected(btnCompileProtoFiles));
-  }
-  
-  /** {@inheritDoc} */
   @Override protected String preferencePageId() {
     return PREFERENCE_PAGE_ID;
   }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/Messages.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/Messages.java
new file mode 100644
index 0000000..b18ade9
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/Messages.java
@@ -0,0 +1,23 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.google.eclipse.protobuf.ui.preferences.paths;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class Messages extends NLS {
+  
+  public static String allProtosInMultipleFolders;
+  public static String allProtosInOneFolder;
+  public static String errorNoFolderNames;
+  public static String importedFilesResolution;
+
+  static {
+    Class<Messages> targetType = Messages.class;
+    NLS.initializeMessages(targetType.getName(), targetType);
+  }
+
+  private Messages() {}
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/Messages.properties b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/Messages.properties
new file mode 100644
index 0000000..5aa3ead
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/Messages.properties
@@ -0,0 +1,4 @@
+allProtosInMultipleFolders=Look for imported files in folders:
+allProtosInOneFolder=One folder for all .proto files
+errorNoFolderNames=Enter the name of the folders
+importedFilesResolution=Resolution of imported files
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferencesInitializer.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferencesInitializer.java
new file mode 100644
index 0000000..68652ac
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferencesInitializer.java
@@ -0,0 +1,32 @@
+/*
+ * 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.paths;
+
+import static com.google.eclipse.protobuf.ui.preferences.paths.PreferenceNames.*;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
+
+/**
+ * Initializes default values for the "Paths" preferences.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class PathsPreferencesInitializer implements IPreferenceStoreInitializer {
+
+  /** {@inheritDoc} */
+  public void initialize(IPreferenceStoreAccess access) {
+    IPreferenceStore store = access.getWritablePreferenceStore();
+    store.setDefault(ALL_PROTOS_IN_ONE_FOLDER_ONLY, true);
+    store.setDefault(PROTOS_IN_MULTIPLE_FOLDERS, false);
+    store.setDefault(FOLDER_NAMES, "");
+  }
+
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PreferenceNames.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PreferenceNames.java
new file mode 100644
index 0000000..444004f
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PreferenceNames.java
@@ -0,0 +1,22 @@
+/*
+ * 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.paths;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+final class PreferenceNames {
+
+  static final String ENABLE_PROJECT_SETTINGS = "paths.enableProjectSettings";
+  static final String ALL_PROTOS_IN_ONE_FOLDER_ONLY = "paths.oneFolderOnly";
+  static final String PROTOS_IN_MULTIPLE_FOLDERS = "paths.multipleFolders";
+  static final String FOLDER_NAMES = "paths.folderNames";
+
+  private PreferenceNames() {}
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PreferencePage.java
index 9513c36..e6c6f55 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PreferencePage.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PreferencePage.java
@@ -8,28 +8,40 @@
  */
 package com.google.eclipse.protobuf.ui.preferences.paths;
 
+import static com.google.eclipse.protobuf.ui.preferences.paths.Messages.*;
+import static com.google.eclipse.protobuf.ui.preferences.paths.PreferenceNames.*;
+import static org.eclipse.core.runtime.IStatus.OK;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.*;
 import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
+import org.eclipse.xtext.util.Strings;
 
 import com.google.eclipse.protobuf.ui.preferences.PreferenceAndPropertyPage;
+import com.google.eclipse.protobuf.ui.util.FolderNameValidator;
 import com.google.inject.Inject;
 
 /**
+ * Preference page for import paths.
+ * 
  * @author alruiz@google.com (Alex Ruiz)
- *
  */
 public class PreferencePage extends PreferenceAndPropertyPage {
 
   private static final String PREFERENCE_PAGE_ID = PreferencePage.class.getName();
 
   private Group grpResolutionOfImported;
-  private Button btnOneFolderFor;
-  private Button btnLookForImported;
+  private Button btnOneFolderOnly;
+  private Button btnMultipleFolders;
   private Text txtFolderNames;
 
+  @Inject private FolderNameValidator folderNameValidator;
+
   @Inject public PreferencePage(IPreferenceStoreAccess preferenceStoreAccess) {
     super(preferenceStoreAccess);
   }
@@ -42,26 +54,84 @@
     grpResolutionOfImported = new Group(contents, SWT.NONE);
     grpResolutionOfImported.setLayout(new GridLayout(1, false));
     grpResolutionOfImported.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
-    grpResolutionOfImported.setText("Resolution of imported files");
+    grpResolutionOfImported.setText(importedFilesResolution);
     
-    btnOneFolderFor = new Button(grpResolutionOfImported, SWT.RADIO);
-    btnOneFolderFor.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-    btnOneFolderFor.setText("One folder for all .proto files");
+    btnOneFolderOnly = new Button(grpResolutionOfImported, SWT.RADIO);
+    btnOneFolderOnly.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
+    btnOneFolderOnly.setText(allProtosInOneFolder);
     
-    btnLookForImported = new Button(grpResolutionOfImported, SWT.RADIO);
-    btnLookForImported.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-    btnLookForImported.setText("Look for imported files in folders:");
+    btnMultipleFolders = new Button(grpResolutionOfImported, SWT.RADIO);
+    btnMultipleFolders.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
+    btnMultipleFolders.setText(allProtosInMultipleFolders);
     
     txtFolderNames = new Text(grpResolutionOfImported, SWT.BORDER);
     txtFolderNames.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
     new Label(contents, SWT.NONE);
+    
+    updateFromPreferenceStore();
+    addEventListeners();
+    
     return contents;
   }
 
+  private void updateFromPreferenceStore() {
+    IPreferenceStore store = doGetPreferenceStore();
+    btnOneFolderOnly.setSelection(store.getBoolean(ALL_PROTOS_IN_ONE_FOLDER_ONLY));
+    btnMultipleFolders.setSelection(store.getBoolean(PROTOS_IN_MULTIPLE_FOLDERS));
+    txtFolderNames.setText(store.getString(FOLDER_NAMES));
+    boolean shouldEnablePathsOptions = true;
+    if (isPropertyPage()) {
+      boolean useProjectSettings = store.getBoolean(ENABLE_PROJECT_SETTINGS);
+      activateProjectSettings(useProjectSettings);
+      shouldEnablePathsOptions = shouldEnablePathsOptions & useProjectSettings;
+    }
+    enableProjectOptions(shouldEnablePathsOptions);
+  }
+
+  private void addEventListeners() {
+    addSelectionListener(new SelectionAdapter() {
+      @Override public void widgetSelected(SelectionEvent e) {
+        boolean selected = btnMultipleFolders.getSelection();
+        txtFolderNames.setEnabled(selected);
+        checkState();
+      }
+    }, btnOneFolderOnly, btnMultipleFolders);
+    txtFolderNames.addModifyListener(new ModifyListener() {
+      public void modifyText(ModifyEvent e) {
+        checkState();
+      }
+    });
+  }
+
+  private void checkState() {
+    if (txtFolderNames.isEnabled()) {
+      String folderNamesTogether = txtFolderNames.getText();
+      if (Strings.isEmpty(folderNamesTogether)) {
+        pageIsNowInvalid(errorNoFolderNames);
+        return;
+      }
+      String[] folderNames = folderNamesTogether.split("[\\s]*,[\\s]*"); //$NON-NLS-1$
+      for (String folderName : folderNames) {
+        IStatus validFolderName = folderNameValidator.validateFolderName(folderName);
+        if (validFolderName.getCode() != OK) {
+          pageIsNowInvalid(validFolderName.getMessage());
+          return;
+        }
+      }
+    }
+    pageIsNowValid();
+  }
+  
   /** {@inheritDoc} */
   @Override protected void onProjectSettingsActivation(boolean active) {
-    // TODO Auto-generated method stub
-
+    enableProjectOptions(active);
+  }
+  
+  private void enableProjectOptions(boolean enabled) {
+    grpResolutionOfImported.setEnabled(enabled);
+    btnOneFolderOnly.setEnabled(enabled);
+    btnMultipleFolders.setEnabled(enabled);
+    txtFolderNames.setEnabled(btnMultipleFolders.getSelection() && enabled);
   }
 
   /** {@inheritDoc} */
@@ -72,7 +142,5 @@
   /** {@inheritDoc} */
   @Override protected void savePreferences() {
     // TODO Auto-generated method stub
-    
   }
-
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/FolderNameValidator.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/FolderNameValidator.java
new file mode 100644
index 0000000..752099b
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/FolderNameValidator.java
@@ -0,0 +1,31 @@
+/*
+ * 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.util;
+
+import static org.eclipse.core.resources.IResource.FOLDER;
+
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IStatus;
+
+import com.google.inject.Singleton;
+
+/**
+ * Validates names of folders.
+ * 
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton
+public class FolderNameValidator {
+
+  public IStatus validateFolderName(String folderName) {
+    IWorkspace workspace = ResourcesPlugin.getWorkspace();
+    return workspace.validateName(folderName, FOLDER);
+  }
+}