Validation for modified project settings step in next project/module wizard?

I've just added a new module type to my custom language plugin and, as part of that work, I'm modifying the project/module creation wizards.  I have this working quite well except for one thing (actually two, but I have a workaround for one).  It's important that the project root and module content roots not be the same directory.  In the project settings step of the wizard during project creation, the top of the screen has text fields for the project name and project root directory and the bottom of the screen has text fields for the module name, content root, and IML file location.  I want to validate the values of these fields before letting the wizard proceed, but I'm having trouble figuring out how to do so.

I can get the module file path in my module builder but not the module content root or the project root (again, particularly during new project creation when the project is null).  Even if I could find this information, I also can't figure out the right way to hook into events so that I can prevent the Next/Finish actions from being allowed when the provided information is invalid, ideally in a graceful manner.

While we're on the topic, is there some way to force the module settings to be expanded/displayed in the ProjectSettingsStep when creating a project?  Obviously I could dig through the Swing component hierarchy to find the correct components, but that's very hacky and fragile.

Any guidance on how to do this is much appreciated!

5 comments
Comment actions Permalink

To do validation in project settings step, you can override modifySettingsStep() in your ModuleBuilder (see com.intellij.openapi.module.WebModuleBuilder for example).
To expand expert settings, you may set SelectTemplateSettings.getInstance().EXPERT_MODE = true.

0
Comment actions Permalink

To do validation in project settings step, you can override modifySettingsStep() in your ModuleBuilder (see com.intellij.openapi.module.WebModuleBuilder for example).
To expand expert settings, you may set SelectTemplateSettings.getInstance().EXPERT_MODE = true.

0
Comment actions Permalink

Turned out that's exactly what I did.

I have this inner class that performs some validations on the project settings. I wrap the original SettingsStep in modifySettingsStep.

 
  public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) {
    return new ProjectSettingsValidation(settingsStep);
  }

  private class ProjectSettingsValidation extends ModuleWizardStep {

    private ProjectSettingsStep myWrappedStep;

    public ProjectSettingsValidation(@NotNull SettingsStep step) {
      myWrappedStep = null;
      if (step instanceof ProjectSettingsStep) {
        myWrappedStep = (ProjectSettingsStep)step;
      }
    }

    @Override
    public JComponent getComponent() {
      return null;
    }

    @Override
    public void updateDataModel() {

    }

    private JTextField findContentRootField(@NotNull Component root) {
      JTextField ret = null;
      if (root instanceof JPanel) {
        for (Component child : ((JPanel)root).getComponents()) {
          ret = findContentRootField(child);
          if (ret != null) {
            return ret;
          }
        }
      } else if (root instanceof JLabel) {
        JLabel label = (JLabel)root;
        if (label.getText().equals("Content root:")) {
          TextFieldWithBrowseButton target = (TextFieldWithBrowseButton)label.getLabelFor();
          return target.getTextField();
        }
      }
      return null;
    }

    @NotNull
    private String getModuleContentRoot() {
      JComponent comp = myWrappedStep.getComponent();
      JTextField contentRootField = findContentRootField(comp);
      assert contentRootField != null;
      return contentRootField.getText();
    }

    @Override
    public boolean validate() throws ConfigurationException {
      if (myWrappedStep == null) {
        return true;
      }

      String moduleContentRoot = getModuleContentRoot();
      // Perform some validation here.

      /* We are executed AFTER the wrapped step, so we don't call validate() on it anymore. */
      return true;
    }
  }


There are two main problems with this approach, however.

1. It's clumsy. As you can see, I need to type cast and look up the GUI component in the wrapped step.

2. The "project directory" is always created, regardless of the returned value of the validate() method. The module directory is not created if validation fails, luckily.

I might have done it wrongly. In that case, any pointer to what's the right way to override modifySettingsStep to do what the OP asked for?

0
Comment actions Permalink

Unfortunately there is no existing API for your task, so hacking is the only way.
As for creating project folder after failed validation, this sounds like a bug, feel free to report it at https://youtrack.jetbrains.com.

0
Comment actions Permalink

Dmitry, one follow-up question.  I've basically been doing what you recommended a few posts back in order to capture some additional configuration information in the project settings step.  I'm still confused as to how I can inject my own validation logic, though.  I can see that ProjectSettingsStep.validate() is called when the user tries to move past that step, and I'd like for some of my own logic to be evaluated at that point.  Overridding validate(Project, Project) in my module builder (where I've overridden modifySettingsStep(SettingsStep)) doesn't kick in until after the project/module directories have been created if necessary.  Any tips on how I might get into the validation flow earlier?

UPDATE: Ignore me for the moment.  I didn't look closely enough at Nam's post with the ModuleWizardStep wrapper class.  Trying that now.

UPDATE 2: Yup, that worked.  Like Nam it's definitely a bit of a hack, but it does work, and it'll save my plugin's users (and therefore me!) some grief from an invalid configuration.  Thanks!

0

Please sign in to leave a comment.