aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java606
1 files changed, 606 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java
new file mode 100644
index 000000000..d04ea897f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java
@@ -0,0 +1,606 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.wizards.newproject;
+
+import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE;
+import static com.android.SdkConstants.OS_SDK_TOOLS_LIB_FOLDER;
+import static com.android.ide.eclipse.adt.AdtUtils.capitalize;
+import static com.android.ide.eclipse.adt.internal.wizards.newproject.ApplicationInfoPage.ACTIVITY_NAME_SUFFIX;
+import static com.android.utils.SdkUtils.stripWhitespace;
+
+import com.android.SdkConstants;
+import com.android.ide.common.xml.ManifestData;
+import com.android.ide.common.xml.ManifestData.Activity;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.VersionCheck;
+import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
+import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode;
+
+import org.eclipse.core.filesystem.URIUtil;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkingSet;
+
+import java.io.File;
+import java.net.URI;
+import java.util.Locale;
+
+/**
+ * Initial page shown when creating projects which asks for the project name,
+ * the the location of the project, working sets, etc.
+ */
+public class ProjectNamePage extends WizardPage implements SelectionListener, ModifyListener {
+ private final NewProjectWizardState mValues;
+ /** Flag used when setting button/text state manually to ignore listener updates */
+ private boolean mIgnore;
+ /** Last user-browsed location, static so that it be remembered for the whole session */
+ private static String sCustomLocationOsPath = ""; //$NON-NLS-1$
+ private static boolean sAutoComputeCustomLocation = true;
+
+ private Text mProjectNameText;
+ private Text mLocationText;
+ private Button mCreateSampleRadioButton;
+ private Button mCreateNewButton;
+ private Button mUseDefaultCheckBox;
+ private Button mBrowseButton;
+ private Label mLocationLabel;
+ private WorkingSetGroup mWorkingSetGroup;
+ /**
+ * Whether we've made sure the Tools are up to date (enough that all the
+ * resources required by the New Project wizard are present -- we don't
+ * necessarily check for newer versions than that here; that's done by
+ * {@link VersionCheck}, though that check doesn't <b>enforce</b> an update
+ * since it needs to allow the user to proceed to access the SDK manager
+ * etc.)
+ */
+ private boolean mCheckedSdkUptodate;
+
+ /**
+ * Create the wizard.
+ * @param values current wizard state
+ */
+ ProjectNamePage(NewProjectWizardState values) {
+ super("projectNamePage"); //$NON-NLS-1$
+ mValues = values;
+
+ setTitle("Create Android Project");
+ setDescription("Select project name and type of project");
+ mWorkingSetGroup = new WorkingSetGroup();
+ setWorkingSets(new IWorkingSet[0]);
+ }
+
+ void init(IStructuredSelection selection, IWorkbenchPart activePart) {
+ setWorkingSets(WorkingSetHelper.getSelectedWorkingSet(selection, activePart));
+ }
+
+ /**
+ * Create contents of the wizard.
+ * @param parent the parent to add the page to
+ */
+ @Override
+ public void createControl(Composite parent) {
+ Composite container = new Composite(parent, SWT.NULL);
+ container.setLayout(new GridLayout(3, false));
+
+ Label nameLabel = new Label(container, SWT.NONE);
+ nameLabel.setText("Project Name:");
+
+ mProjectNameText = new Text(container, SWT.BORDER);
+ mProjectNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ mProjectNameText.addModifyListener(this);
+
+ if (mValues.mode != Mode.TEST) {
+ mCreateNewButton = new Button(container, SWT.RADIO);
+ mCreateNewButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ mCreateNewButton.setText("Create new project in workspace");
+ mCreateNewButton.addSelectionListener(this);
+
+ // TBD: Should we hide this completely, and make samples something you only invoke
+ // from the "New Sample Project" wizard?
+ mCreateSampleRadioButton = new Button(container, SWT.RADIO);
+ mCreateSampleRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+ 3, 1));
+ mCreateSampleRadioButton.setText("Create project from existing sample");
+ mCreateSampleRadioButton.addSelectionListener(this);
+ }
+
+ Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
+
+ mUseDefaultCheckBox = new Button(container, SWT.CHECK);
+ mUseDefaultCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ mUseDefaultCheckBox.setText("Use default location");
+ mUseDefaultCheckBox.addSelectionListener(this);
+
+ mLocationLabel = new Label(container, SWT.NONE);
+ mLocationLabel.setText("Location:");
+
+ mLocationText = new Text(container, SWT.BORDER);
+ mLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ mLocationText.addModifyListener(this);
+
+ mBrowseButton = new Button(container, SWT.NONE);
+ mBrowseButton.setText("Browse...");
+ mBrowseButton.addSelectionListener(this);
+
+ Composite group = mWorkingSetGroup.createControl(container);
+ group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1));
+
+ setControl(container);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+
+ if (visible) {
+ try {
+ mIgnore = true;
+ if (mValues.projectName != null) {
+ mProjectNameText.setText(mValues.projectName);
+ mProjectNameText.setFocus();
+ }
+ if (mValues.mode == Mode.ANY || mValues.mode == Mode.TEST) {
+ if (mValues.useExisting) {
+ assert false; // This is now handled by the separate import wizard
+ } else if (mCreateNewButton != null) {
+ mCreateNewButton.setSelection(true);
+ }
+ } else if (mValues.mode == Mode.SAMPLE) {
+ mCreateSampleRadioButton.setSelection(true);
+ }
+ if (mValues.projectLocation != null) {
+ mLocationText.setText(mValues.projectLocation.getPath());
+ }
+ mUseDefaultCheckBox.setSelection(mValues.useDefaultLocation);
+ updateLocationState();
+ } finally {
+ mIgnore = false;
+ }
+ }
+
+ validatePage();
+ }
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (mIgnore) {
+ return;
+ }
+
+ Object source = e.getSource();
+
+ if (source == mProjectNameText) {
+ onProjectFieldModified();
+ if (!mValues.useDefaultLocation && !mValues.projectLocationModifiedByUser) {
+ updateLocationPathField(null);
+ }
+ } else if (source == mLocationText) {
+ mValues.projectLocationModifiedByUser = true;
+ if (!mValues.useDefaultLocation) {
+ File f = new File(mLocationText.getText().trim());
+ mValues.projectLocation = f;
+ if (f.exists() && f.isDirectory() && !f.equals(mValues.projectLocation)) {
+ updateLocationPathField(mValues.projectLocation.getPath());
+ }
+ }
+ }
+
+ validatePage();
+ }
+
+ private void onProjectFieldModified() {
+ mValues.projectName = mProjectNameText.getText().trim();
+ mValues.projectNameModifiedByUser = true;
+
+ if (!mValues.applicationNameModifiedByUser) {
+ mValues.applicationName = capitalize(mValues.projectName);
+ if (!mValues.testApplicationNameModified) {
+ mValues.testApplicationName =
+ ApplicationInfoPage.suggestTestApplicationName(mValues.applicationName);
+ }
+ }
+ if (!mValues.activityNameModifiedByUser) {
+ String name = capitalize(mValues.projectName);
+ mValues.activityName = stripWhitespace(name) + ACTIVITY_NAME_SUFFIX;
+ }
+ if (!mValues.testProjectModified) {
+ mValues.testProjectName =
+ ApplicationInfoPage.suggestTestProjectName(mValues.projectName);
+ }
+ if (!mValues.projectLocationModifiedByUser) {
+ updateLocationPathField(null);
+ }
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (mIgnore) {
+ return;
+ }
+
+ Object source = e.getSource();
+
+ if (source == mCreateNewButton && mCreateNewButton != null
+ && mCreateNewButton.getSelection()) {
+ mValues.useExisting = false;
+ if (mValues.mode == Mode.SAMPLE) {
+ // Only reset the mode if we're toggling from sample back to create new
+ // or create existing. We can only come to the sample state when we're in
+ // ANY mode. (In particular, we don't want to switch to ANY if you're
+ // in test mode.
+ mValues.mode = Mode.ANY;
+ }
+ updateLocationState();
+ } else if (source == mCreateSampleRadioButton && mCreateSampleRadioButton.getSelection()) {
+ mValues.useExisting = true;
+ mValues.useDefaultLocation = true;
+ if (!mUseDefaultCheckBox.getSelection()) {
+ try {
+ mIgnore = true;
+ mUseDefaultCheckBox.setSelection(true);
+ } finally {
+ mIgnore = false;
+ }
+ }
+ mValues.mode = Mode.SAMPLE;
+ updateLocationState();
+ } else if (source == mUseDefaultCheckBox) {
+ mValues.useDefaultLocation = mUseDefaultCheckBox.getSelection();
+ updateLocationState();
+ } else if (source == mBrowseButton) {
+ onOpenDirectoryBrowser();
+ }
+
+ validatePage();
+ }
+
+ /**
+ * Enables or disable the location widgets depending on the user selection:
+ * the location path is enabled when using the "existing source" mode (i.e. not new project)
+ * or in new project mode with the "use default location" turned off.
+ */
+ private void updateLocationState() {
+ boolean isNewProject = !mValues.useExisting;
+ boolean isCreateFromSample = mValues.mode == Mode.SAMPLE;
+ boolean useDefault = mValues.useDefaultLocation && !isCreateFromSample;
+ boolean locationEnabled = (!isNewProject || !useDefault) && !isCreateFromSample;
+
+ mUseDefaultCheckBox.setEnabled(isNewProject);
+ mLocationLabel.setEnabled(locationEnabled);
+ mLocationText.setEnabled(locationEnabled);
+ mBrowseButton.setEnabled(locationEnabled);
+
+ updateLocationPathField(null);
+ }
+
+ /**
+ * Display a directory browser and update the location path field with the selected path
+ */
+ private void onOpenDirectoryBrowser() {
+
+ String existingDir = mLocationText.getText().trim();
+
+ // Disable the path if it doesn't exist
+ if (existingDir.length() == 0) {
+ existingDir = null;
+ } else {
+ File f = new File(existingDir);
+ if (!f.exists()) {
+ existingDir = null;
+ }
+ }
+
+ DirectoryDialog directoryDialog = new DirectoryDialog(mLocationText.getShell());
+ directoryDialog.setMessage("Browse for folder");
+ directoryDialog.setFilterPath(existingDir);
+ String dir = directoryDialog.open();
+
+ if (dir != null) {
+ updateLocationPathField(dir);
+ validatePage();
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+
+ /**
+ * Returns the working sets to which the new project should be added.
+ *
+ * @return the selected working sets to which the new project should be added
+ */
+ private IWorkingSet[] getWorkingSets() {
+ return mWorkingSetGroup.getSelectedWorkingSets();
+ }
+
+ /**
+ * Sets the working sets to which the new project should be added.
+ *
+ * @param workingSets the initial selected working sets
+ */
+ private void setWorkingSets(IWorkingSet[] workingSets) {
+ assert workingSets != null;
+ mWorkingSetGroup.setWorkingSets(workingSets);
+ }
+
+ /**
+ * Updates the location directory path field.
+ * <br/>
+ * When custom user selection is enabled, use the absDir argument if not null and also
+ * save it internally. If absDir is null, restore the last saved absDir. This allows the
+ * user selection to be remembered when the user switches from default to custom.
+ * <br/>
+ * When custom user selection is disabled, use the workspace default location with the
+ * current project name. This does not change the internally cached absDir.
+ *
+ * @param absDir A new absolute directory path or null to use the default.
+ */
+ private void updateLocationPathField(String absDir) {
+ boolean isNewProject = !mValues.useExisting || mValues.mode == Mode.SAMPLE;
+ boolean useDefault = mValues.useDefaultLocation;
+ boolean customLocation = !isNewProject || !useDefault;
+
+ if (!mIgnore) {
+ try {
+ mIgnore = true;
+ if (customLocation) {
+ if (absDir != null) {
+ // We get here if the user selected a directory with the "Browse" button.
+ // Disable auto-compute of the custom location unless the user selected
+ // the exact same path.
+ sAutoComputeCustomLocation = sAutoComputeCustomLocation &&
+ absDir.equals(sCustomLocationOsPath);
+ sCustomLocationOsPath = TextProcessor.process(absDir);
+ } else if (sAutoComputeCustomLocation ||
+ (!isNewProject && !new File(sCustomLocationOsPath).isDirectory())) {
+ // As a default import location, just suggest the home directory; the user
+ // needs to point to a project to import.
+ // TODO: Open file chooser automatically?
+ sCustomLocationOsPath = System.getProperty("user.home"); //$NON-NLS-1$
+ }
+ if (!mLocationText.getText().equals(sCustomLocationOsPath)) {
+ mLocationText.setText(sCustomLocationOsPath);
+ mValues.projectLocation = new File(sCustomLocationOsPath);
+ }
+ } else {
+ String value = Platform.getLocation().append(mValues.projectName).toString();
+ value = TextProcessor.process(value);
+ if (!mLocationText.getText().equals(value)) {
+ mLocationText.setText(value);
+ mValues.projectLocation = new File(value);
+ }
+ }
+ } finally {
+ mIgnore = false;
+ }
+ }
+
+ if (mValues.useExisting && mValues.projectLocation != null
+ && mValues.projectLocation.exists() && mValues.mode != Mode.SAMPLE) {
+ mValues.extractFromAndroidManifest(new Path(mValues.projectLocation.getPath()));
+ if (!mValues.projectNameModifiedByUser && mValues.projectName != null) {
+ try {
+ mIgnore = true;
+ mProjectNameText.setText(mValues.projectName);
+ } finally {
+ mIgnore = false;
+ }
+ }
+ }
+ }
+
+ private void validatePage() {
+ IStatus status = null;
+
+ // Validate project name -- unless we're creating a sample, in which case
+ // the user will get a chance to pick the name on the Sample page
+ if (mValues.mode != Mode.SAMPLE) {
+ status = validateProjectName(mValues.projectName);
+ }
+
+ if (status == null || status.getSeverity() != IStatus.ERROR) {
+ IStatus validLocation = validateLocation();
+ if (validLocation != null) {
+ status = validLocation;
+ }
+ }
+
+ if (!mCheckedSdkUptodate) {
+ // Ensure that we have a recent enough version of the Tools that the right templates
+ // are available
+ File file = new File(AdtPlugin.getOsSdkFolder(), OS_SDK_TOOLS_LIB_FOLDER
+ + File.separator + FN_PROJECT_PROGUARD_FILE);
+ if (!file.exists()) {
+ status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format("You do not have the latest version of the "
+ + "SDK Tools installed: Please update. (Missing %1$s)", file.getPath()));
+ } else {
+ mCheckedSdkUptodate = true;
+ }
+ }
+
+ // -- update UI & enable finish if there's no error
+ setPageComplete(status == null || status.getSeverity() != IStatus.ERROR);
+ if (status != null) {
+ setMessage(status.getMessage(),
+ status.getSeverity() == IStatus.ERROR
+ ? IMessageProvider.ERROR : IMessageProvider.WARNING);
+ } else {
+ setErrorMessage(null);
+ setMessage(null);
+ }
+ }
+
+ private IStatus validateLocation() {
+ if (mValues.mode == Mode.SAMPLE) {
+ // Samples are always created in the default directory
+ return null;
+ }
+
+ // Validate location
+ Path path = new Path(mValues.projectLocation.getPath());
+ if (!mValues.useExisting) {
+ if (!mValues.useDefaultLocation) {
+ // If not using the default value validate the location.
+ URI uri = URIUtil.toURI(path.toOSString());
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IProject handle = workspace.getRoot().getProject(mValues.projectName);
+ IStatus locationStatus = workspace.validateProjectLocationURI(handle, uri);
+ if (!locationStatus.isOK()) {
+ return locationStatus;
+ }
+ // The location is valid as far as Eclipse is concerned (i.e. mostly not
+ // an existing workspace project.) Check it either doesn't exist or is
+ // a directory that is empty.
+ File f = path.toFile();
+ if (f.exists() && !f.isDirectory()) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ "A directory name must be specified.");
+ } else if (f.isDirectory()) {
+ // However if the directory exists, we should put a
+ // warning if it is not empty. We don't put an error
+ // (we'll ask the user again for confirmation before
+ // using the directory.)
+ String[] l = f.list();
+ if (l != null && l.length != 0) {
+ return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID,
+ "The selected output directory is not empty.");
+ }
+ }
+ } else {
+ // Otherwise validate the path string is not empty
+ if (mValues.projectLocation.getPath().length() == 0) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ "A directory name must be specified.");
+ }
+ File dest = path.toFile();
+ if (dest.exists()) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format(
+ "There is already a file or directory named \"%1$s\" in the selected location.",
+ mValues.projectName));
+ }
+ }
+ } else {
+ // Must be an existing directory
+ File f = path.toFile();
+ if (!f.isDirectory()) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ "An existing directory name must be specified.");
+ }
+
+ // Check there's an android manifest in the directory
+ String osPath = path.append(SdkConstants.FN_ANDROID_MANIFEST_XML).toOSString();
+ File manifestFile = new File(osPath);
+ if (!manifestFile.isFile()) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format(
+ "Choose a valid Android code directory\n" +
+ "(%1$s not found in %2$s.)",
+ SdkConstants.FN_ANDROID_MANIFEST_XML, f.getName()));
+ }
+
+ // Parse it and check the important fields.
+ ManifestData manifestData = AndroidManifestHelper.parseForData(osPath);
+ if (manifestData == null) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format("File %1$s could not be parsed.", osPath));
+ }
+ String packageName = manifestData.getPackage();
+ if (packageName == null || packageName.length() == 0) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format("No package name defined in %1$s.", osPath));
+ }
+ Activity[] activities = manifestData.getActivities();
+ if (activities == null || activities.length == 0) {
+ // This is acceptable now as long as no activity needs to be
+ // created
+ if (mValues.createActivity) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format("No activity name defined in %1$s.", osPath));
+ }
+ }
+
+ // If there's already a .project, tell the user to use import instead.
+ if (path.append(".project").toFile().exists()) { //$NON-NLS-1$
+ return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID,
+ "An Eclipse project already exists in this directory.\n" +
+ "Consider using File > Import > Existing Project instead.");
+ }
+ }
+
+ return null;
+ }
+
+ public static IStatus validateProjectName(String projectName) {
+ if (projectName == null || projectName.length() == 0) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ "Project name must be specified");
+ } else {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IStatus nameStatus = workspace.validateName(projectName, IResource.PROJECT);
+ if (!nameStatus.isOK()) {
+ return nameStatus;
+ } else {
+ // Note: the case-sensitiveness of the project name matters and can cause a
+ // conflict *later* when creating the project resource, so let's check it now.
+ for (IProject existingProj : workspace.getRoot().getProjects()) {
+ if (projectName.equalsIgnoreCase(existingProj.getName())) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ "A project with that name already exists in the workspace");
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public IWizardPage getNextPage() {
+ // Sync working set data to the value object, since the WorkingSetGroup
+ // doesn't let us add listeners to do this lazily
+ mValues.workingSets = getWorkingSets();
+
+ return super.getNextPage();
+ }
+}