In progress: [ Issue 40 ] Add support for import resolution across multiple folders https://code.google.com/p/protobuf-dt/issues/detail?id=40 Replaced text field with list for names of directories to be included in URI resolution. Code cleanup.
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java deleted file mode 100644 index 9a41d2e..0000000 --- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/FileUriResolver_resolveUri_Test.java +++ /dev/null
@@ -1,93 +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.scoping; - -import static com.google.eclipse.protobuf.ui.preferences.paths.PathResolutionType.SINGLE_DIRECTORY; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; - -import org.eclipse.core.resources.IProject; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.junit.*; - -import com.google.eclipse.protobuf.junit.core.XtextRule; -import com.google.eclipse.protobuf.junit.stubs.ResourceStub; -import com.google.eclipse.protobuf.scoping.IFileUriResolver; -import com.google.eclipse.protobuf.ui.preferences.paths.*; -import com.google.inject.*; - -/** - * Tests for <code>{@link FileUriResolver#resolveUri(String, Resource)}</code>. - * - * @author alruiz@google.com (Alex Ruiz) - */ -public class FileUriResolver_resolveUri_Test { - - @Rule public XtextRule xtext = new XtextRule(); - - private Resource resource; - private PathsPreferenceReader preferenceReader; - private PathsPreferences preferences; - private IProject project; - private Resources resources; - - private FileUriResolver resolver; - - @Before public void setUp() { - resource = new ResourceStub("platform:/resource/src/proto/person.proto"); - preferenceReader = mock(PathsPreferenceReader.class); - preferences = mock(PathsPreferences.class); - project = mock(IProject.class); - resources = mock(Resources.class); - Module module = new Module() { - public void configure(Binder binder) { - binder.bind(PathsPreferenceReader.class).toInstance(preferenceReader); - binder.bind(Resources.class).toInstance(resources); - binder.bind(IFileUriResolver.class).to(FileUriResolver.class); - } - }; - Injector injector = xtext.injector().createChildInjector(module); - resolver = (FileUriResolver) injector.getInstance(IFileUriResolver.class); - } - - @Test public void should_resolve_import_URI_if_missing_scheme() { - callStubs(SINGLE_DIRECTORY, true); - String resolved = resolver.resolveUri("folder1/address.proto", resource); - assertThat(resolved, equalTo("platform:/resource/src/proto/folder1/address.proto")); - } - - @Test public void should_not_resolve_import_URI_if_not_missing_scheme() { - callStubs(SINGLE_DIRECTORY, true); - String original = "platform:/resource/src/proto/folder1/address.proto"; - String resolved = resolver.resolveUri(original, resource); - assertThat(resolved, equalTo(original)); - } - - @Test public void should_resolve_import_URI_even_if_overlapping_folders_with_resource_URI() { - callStubs(SINGLE_DIRECTORY, true); - String resolved = resolver.resolveUri("src/proto/folder1/address.proto", resource); - assertThat(resolved, equalTo("platform:/resource/src/proto/folder1/address.proto")); - } - - @Test public void should_resolve_import_URI_even_if_overlapping_one_folder_only_with_resource_URI() { - callStubs(SINGLE_DIRECTORY, true); - String resolved = resolver.resolveUri("src/proto/read-only/address.proto", resource); - assertThat(resolved, equalTo("platform:/resource/src/proto/read-only/address.proto")); - } - - private void callStubs(PathResolutionType type, boolean resolvedUriExists) { - when(resources.project(resource.getURI())).thenReturn(project); - when(preferenceReader.readFromPrefereceStore(project)).thenReturn(preferences); - when(preferences.pathResolutionType()).thenReturn(type); - when(resources.fileExists(any(URI.class))).thenReturn(resolvedUriExists); - } -}
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 new file mode 100644 index 0000000..c1fc418 --- /dev/null +++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/scoping/SingleDirectoryFileResolver_resolveUri_Test.java
@@ -0,0 +1,65 @@ +/* + * 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.scoping; + +import static org.eclipse.emf.common.util.URI.createURI; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +import org.eclipse.core.resources.IProject; +import org.eclipse.emf.common.util.URI; +import org.junit.*; + +import com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferences; + +/** + * Tests for <code>{@link SingleDirectoryFileResolver#resolveUri(String, URI, PathsPreferences, IProject)}</code>. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class SingleDirectoryFileResolver_resolveUri_Test { + + private static URI resourceUri; + private static PathsPreferences preferences; + private static IProject project; + + @BeforeClass public static void setUpOnce() { + resourceUri = createURI("platform:/resource/src/proto/person.proto"); + preferences = mock(PathsPreferences.class); + project = mock(IProject.class); + } + + private Resources resources; + private SingleDirectoryFileResolver resolver; + + @Before public void setUp() { + resources = mock(Resources.class); + resolver = new SingleDirectoryFileResolver(resources); + } + + @Test public void should_resolve_import_URI_if_missing_scheme() { + when(resources.fileExists(any(URI.class))).thenReturn(true); + String resolved = resolver.resolveUri("folder1/address.proto", resourceUri, preferences, project); + assertThat(resolved, equalTo("platform:/resource/src/proto/folder1/address.proto")); + } + + @Test public void should_resolve_import_URI_even_if_overlapping_folders_with_resource_URI() { + when(resources.fileExists(any(URI.class))).thenReturn(true); + String resolved = resolver.resolveUri("src/proto/folder1/address.proto", resourceUri, preferences, project); + assertThat(resolved, equalTo("platform:/resource/src/proto/folder1/address.proto")); + } + + @Test public void should_resolve_import_URI_even_if_overlapping_one_folder_only_with_resource_URI() { + when(resources.fileExists(any(URI.class))).thenReturn(true); + String resolved = resolver.resolveUri("src/proto/read-only/address.proto", resourceUri, preferences, project); + assertThat(resolved, equalTo("platform:/resource/src/proto/read-only/address.proto")); + } +}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferencePage.java index f8fd406..8f12479 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferencePage.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/compiler/CompilerPreferencePage.java
@@ -8,24 +8,21 @@ */ package com.google.eclipse.protobuf.ui.preferences.compiler; -import static com.google.eclipse.protobuf.ui.preferences.compiler.Messages.*; import static com.google.eclipse.protobuf.ui.preferences.compiler.CompilerPreferenceNames.*; -import static org.eclipse.core.runtime.IStatus.OK; +import static com.google.eclipse.protobuf.ui.preferences.compiler.Messages.*; import static org.eclipse.xtext.util.Strings.isEmpty; import java.io.File; -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.layout.*; import org.eclipse.swt.widgets.*; 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.eclipse.protobuf.ui.util.DirectoryNameValidator; import com.google.inject.Inject; /** @@ -59,8 +56,8 @@ private Button btnRefreshOutputFolder; private Label lblOutputFolderRelative; - @Inject private FolderNameValidator folderNameValidator; - + @Inject private DirectoryNameValidator directoryNameValidator; + @Inject public CompilerPreferencePage(IPreferenceStoreAccess preferenceStoreAccess) { super(preferenceStoreAccess); } @@ -231,9 +228,9 @@ pageIsNowInvalid(errorNoOutputFolderName); return; } - IStatus validFolderName = folderNameValidator.validateFolderName(folderName); - if (validFolderName.getCode() != OK) { - pageIsNowInvalid(validFolderName.getMessage()); + String invalidDirectoryName = directoryNameValidator.validateDirectoryName(folderName); + if (invalidDirectoryName != null) { + pageIsNowInvalid(invalidDirectoryName); return; } if (!customPathOptionSelectedAndEnabled()) { @@ -278,7 +275,7 @@ enableCompilerOptions(enableCompilerOptions); super.performDefaults(); } - + /** {@inheritDoc} */ @Override protected void onProjectSettingsActivation(boolean active) { enableProjectSpecificOptions(active); @@ -358,7 +355,7 @@ store.setValue(REFRESH_PROJECT, btnRefreshProject.getSelection()); store.setValue(REFRESH_OUTPUT_FOLDER, btnRefreshOutputFolder.getSelection()); } - + /** {@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/DirectoryNamesEditor.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryNamesEditor.java new file mode 100644 index 0000000..f056d89 --- /dev/null +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/DirectoryNamesEditor.java
@@ -0,0 +1,176 @@ +/* + * 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.Messages.*; +import static java.util.Arrays.asList; +import static java.util.Collections.unmodifiableList; +import static org.eclipse.jface.window.Window.OK; +import static org.eclipse.xtext.util.Strings.isEmpty; + +import java.util.Collection; + +import org.eclipse.jface.dialogs.*; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.layout.*; +import org.eclipse.swt.widgets.*; + +import com.google.eclipse.protobuf.ui.util.DirectoryNameValidator; + +/** + * Editor where users can add/remove the directories to be used for URI resolution. + * + * @author alruiz@google.com (Alex Ruiz) + */ +public class DirectoryNamesEditor extends Composite { + + private final DirectoryNameValidator directoryNameValidator; + + private List lstDirectoryNames; + private final Button btnAdd; + private final Button btnRemove; + private final Button btnUp; + private final Button btnDown; + + private SelectionListener onRemoveListener; + + /** + * Creates a new </code>{@link DirectoryNamesEditor}</code>. + * @param parent a widget which will be the parent of the new instance (cannot be {@code null}.) + * @param directoryNameValidator validates that a {@code String} is a valid directory name. + */ + public DirectoryNamesEditor(Composite parent, DirectoryNameValidator directoryNameValidator) { + super(parent, SWT.NONE); + this.directoryNameValidator = directoryNameValidator; + setLayout(new GridLayout(3, false)); + + lstDirectoryNames = new List(this, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI); + lstDirectoryNames.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); + + Composite composite = new Composite(this, SWT.NONE); + composite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1)); + composite.setLayout(new GridLayout(1, false)); + + btnAdd = new Button(composite, SWT.NONE); + btnAdd.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + btnAdd.setText(add); + + btnRemove = new Button(composite, SWT.NONE); + btnRemove.setEnabled(false); + btnRemove.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + btnRemove.setText(remove); + + btnUp = new Button(composite, SWT.NONE); + btnUp.setEnabled(false); + btnUp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + btnUp.setText(up); + + btnDown = new Button(composite, SWT.NONE); + btnDown.setEnabled(false); + btnDown.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + btnDown.setText(down); + + addEventListeners(); + } + + private void addEventListeners() { + lstDirectoryNames.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + lstDirectoryNames = null; + } + }); + lstDirectoryNames.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + enableButtonsDependingOnListSelection(); + } + }); + btnAdd.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + IInputValidator validator = new IInputValidator() { + public String isValid(String newText) { + if (isEmpty(newText)) return Messages.errorEmptyDirectoryName; + return directoryNameValidator.validateDirectoryName(newText); + } + }; + InputDialog input = new InputDialog(getShell(), directoryNameInputTitle, directoryNameInputMessage, null, validator); + if (input.open() == OK) { + lstDirectoryNames.add(input.getValue()); + } + } + }); + btnRemove.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + int index = lstDirectoryNames.getSelectionIndex(); + if (index < 0) return; + lstDirectoryNames.remove(index); + enableButtonsDependingOnListSelection(); + } + }); + btnUp.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + swap(true); + } + }); + btnDown.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + swap(false); + } + }); + } + + private void swap(boolean goUp) { + int index = lstDirectoryNames.getSelectionIndex(); + if (index < 0) return; + int target = goUp ? index - 1 : index + 1; + String[] selection = lstDirectoryNames.getSelection(); + lstDirectoryNames.remove(index); + lstDirectoryNames.add(selection[0], target); + lstDirectoryNames.setSelection(target); + enableButtonsDependingOnListSelection(); + } + + /** {@inheritDoc} */ + @Override public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + lstDirectoryNames.setEnabled(enabled); + btnAdd.setEnabled(enabled); + if (enabled) { + enableButtonsDependingOnListSelection(); + } else { + btnRemove.setEnabled(false); + btnUp.setEnabled(false); + btnDown.setEnabled(false); + } + } + + private void enableButtonsDependingOnListSelection() { + int selectionIndex = lstDirectoryNames.getSelectionIndex(); + int size = lstDirectoryNames.getItemCount(); + boolean hasSelection = selectionIndex >= 0; + btnRemove.setEnabled(hasSelection); + boolean hasElements = size > 1; + btnUp.setEnabled(hasElements && selectionIndex > 0); + btnDown.setEnabled(hasElements && hasSelection && selectionIndex < size - 1); + } + + public java.util.List<String> directoryNames() { + return unmodifiableList(asList(lstDirectoryNames.getItems())); + } + + public void addDirectoryNames(Collection<String> directoryNames) { + for (String name : directoryNames) lstDirectoryNames.add(name); + } + + public void onRemove(SelectionListener listener) { + if (onRemoveListener != null) lstDirectoryNames.removeSelectionListener(onRemoveListener); + onRemoveListener = listener; + lstDirectoryNames.addSelectionListener(onRemoveListener); + } +}
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 index 83e2534..ef56359 100644 --- 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
@@ -14,12 +14,18 @@ * @author alruiz@google.com (Alex Ruiz) */ public class Messages extends NLS { - - public static String directoryNameHint; + + public static String add; + public static String directoryNameInputMessage; + public static String directoryNameInputTitle; + public static String down; + public static String errorEmptyDirectoryName; public static String errorNoDirectoryNames; public static String filesInMultipleDirectories; public static String filesInOneDirectoryOnly; public static String importedFilesPathResolution; + public static String remove; + public static String up; static { Class<Messages> targetType = Messages.class;
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 index 8424e7e..0322aa3 100644 --- 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
@@ -1,5 +1,11 @@ -directoryNameHint=*comma-separated values (e.g. 'src, src-gen, src-readonly') -errorNoDirectoryNames=Enter the name of the directories -filesInMultipleDirectories=Look for imported files in directories:* +add=&Add +directoryNameInputMessage=Enter directory name: +directoryNameInputTitle=Path Resolution +down=&Down +errorEmptyDirectoryName=The name of the directory should not be empty +errorNoDirectoryNames=Enter the names of the directories +filesInMultipleDirectories=Look for imported files in directories: filesInOneDirectoryOnly=One directory for all .proto files importedFilesPathResolution=Path resolution of imported files +remove=&Remove +up=&Up
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferencePage.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferencePage.java index de99706..c2789e0 100644 --- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferencePage.java +++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/paths/PathsPreferencePage.java
@@ -10,38 +10,35 @@ import static com.google.eclipse.protobuf.ui.preferences.paths.Messages.*; import static com.google.eclipse.protobuf.ui.preferences.paths.PathsPreferenceNames.*; -import static com.google.eclipse.protobuf.ui.util.Strings.CSV_PATTERN; -import static org.eclipse.core.runtime.IStatus.OK; -import static org.eclipse.xtext.util.Strings.isEmpty; +import static org.eclipse.xtext.util.Strings.*; -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.layout.*; import org.eclipse.swt.widgets.*; 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.eclipse.protobuf.ui.util.DirectoryNameValidator; import com.google.inject.Inject; /** * Preference page for import paths. - * + * * @author alruiz@google.com (Alex Ruiz) */ public class PathsPreferencePage extends PreferenceAndPropertyPage { + private static final String COMMA_DELIMITER = ","; private static final String PREFERENCE_PAGE_ID = PathsPreferencePage.class.getName(); private Group grpResolutionOfImported; private Button btnOneFolderOnly; private Button btnMultipleFolders; - private Text txtFolderNames; + private DirectoryNamesEditor directoryNamesEditor; - @Inject private FolderNameValidator folderNameValidator; + @Inject private DirectoryNameValidator directoryNameValidator; @Inject public PathsPreferencePage(IPreferenceStoreAccess preferenceStoreAccess) { super(preferenceStoreAccess); @@ -51,30 +48,27 @@ @Override protected Control createContents(Composite parent) { // generated by WindowBuilder Composite contents = contentsComposite(parent); - + 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(importedFilesPathResolution); - + btnOneFolderOnly = new Button(grpResolutionOfImported, SWT.RADIO); btnOneFolderOnly.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); btnOneFolderOnly.setText(filesInOneDirectoryOnly); - + btnMultipleFolders = new Button(grpResolutionOfImported, SWT.RADIO); btnMultipleFolders.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); btnMultipleFolders.setText(filesInMultipleDirectories); - - txtFolderNames = new Text(grpResolutionOfImported, SWT.BORDER); - txtFolderNames.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - - Label label = new Label(grpResolutionOfImported, SWT.NONE); - label.setText(directoryNameHint); + + directoryNamesEditor = new DirectoryNamesEditor(grpResolutionOfImported, directoryNameValidator); + directoryNamesEditor.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); new Label(contents, SWT.NONE); - + updateFromPreferenceStore(); addEventListeners(); - + return contents; } @@ -82,7 +76,7 @@ IPreferenceStore store = doGetPreferenceStore(); btnOneFolderOnly.setSelection(store.getBoolean(FILES_IN_ONE_DIRECTORY_ONLY)); btnMultipleFolders.setSelection(store.getBoolean(FILES_IN_MULTIPLE_DIRECTORIES)); - txtFolderNames.setText(store.getString(DIRECTORY_NAMES)); + setDirectoryNames(store.getString(DIRECTORY_NAMES)); boolean shouldEnablePathsOptions = true; if (isPropertyPage()) { boolean useProjectSettings = store.getBoolean(ENABLE_PROJECT_SETTINGS); @@ -96,35 +90,25 @@ addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { boolean selected = btnMultipleFolders.getSelection(); - txtFolderNames.setEnabled(selected); + directoryNamesEditor.setEnabled(selected); checkState(); } }, btnOneFolderOnly, btnMultipleFolders); - txtFolderNames.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { + directoryNamesEditor.onRemove(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { checkState(); } }); } private void checkState() { - if (txtFolderNames.isEnabled()) { - String folderNames = txtFolderNames.getText().trim(); - if (isEmpty(folderNames)) { - pageIsNowInvalid(errorNoDirectoryNames); - return; - } - for (String folderName : folderNames.split(CSV_PATTERN)) { - IStatus validFolderName = folderNameValidator.validateFolderName(folderName); - if (validFolderName.getCode() != OK) { - pageIsNowInvalid(validFolderName.getMessage()); - return; - } - } + if (directoryNamesEditor.isEnabled() && directoryNamesEditor.directoryNames().isEmpty()) { + pageIsNowInvalid(errorNoDirectoryNames); + return; } pageIsNowValid(); } - + /** {@inheritDoc} */ @Override protected void onProjectSettingsActivation(boolean active) { enableProjectOptions(active); @@ -134,7 +118,7 @@ IPreferenceStore store = doGetPreferenceStore(); btnOneFolderOnly.setSelection(store.getDefaultBoolean(FILES_IN_ONE_DIRECTORY_ONLY)); btnMultipleFolders.setSelection(store.getDefaultBoolean(FILES_IN_MULTIPLE_DIRECTORIES)); - txtFolderNames.setText(store.getDefaultString(DIRECTORY_NAMES)); + setDirectoryNames(store.getDefaultString(DIRECTORY_NAMES)); boolean shouldEnablePathsOptions = true; if (isPropertyPage()) { boolean useProjectSettings = store.getDefaultBoolean(ENABLE_PROJECT_SETTINGS); @@ -144,21 +128,29 @@ enableProjectOptions(shouldEnablePathsOptions); super.performDefaults(); } - + + private void setDirectoryNames(String directoryNames) { + directoryNamesEditor.addDirectoryNames(split(directoryNames, COMMA_DELIMITER)); + } + private void enableProjectOptions(boolean enabled) { grpResolutionOfImported.setEnabled(enabled); btnOneFolderOnly.setEnabled(enabled); btnMultipleFolders.setEnabled(enabled); - txtFolderNames.setEnabled(btnMultipleFolders.getSelection() && enabled); + directoryNamesEditor.setEnabled(btnMultipleFolders.getSelection() && enabled); } - + /** {@inheritDoc} */ @Override protected void savePreferences() { IPreferenceStore store = getPreferenceStore(); if (isPropertyPage()) store.setValue(ENABLE_PROJECT_SETTINGS, areProjectSettingsActive()); store.setValue(FILES_IN_ONE_DIRECTORY_ONLY, btnOneFolderOnly.getSelection()); store.setValue(FILES_IN_MULTIPLE_DIRECTORIES, btnMultipleFolders.getSelection()); - store.setValue(DIRECTORY_NAMES, txtFolderNames.getText().trim()); + store.setValue(DIRECTORY_NAMES, directoryNames()); + } + + private String directoryNames() { + return concat(COMMA_DELIMITER, directoryNamesEditor.directoryNames()); } /** {@inheritDoc} */
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/DirectoryNameValidator.java similarity index 66% rename from com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/FolderNameValidator.java rename to com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/util/DirectoryNameValidator.java index 752099b..bf5253d 100644 --- 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/DirectoryNameValidator.java
@@ -9,23 +9,24 @@ package com.google.eclipse.protobuf.ui.util; import static org.eclipse.core.resources.IResource.FOLDER; +import static org.eclipse.core.runtime.IStatus.OK; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.*; 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 class DirectoryNameValidator { - public IStatus validateFolderName(String folderName) { + public String validateDirectoryName(String directoryName) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); - return workspace.validateName(folderName, FOLDER); + IStatus isValid = workspace.validateName(directoryName, FOLDER); + return (isValid.getCode() == OK) ? null : isValid.getMessage(); } }