2025-05-12 11:32:03 +02:00

18 KiB

New Project Wizard

Implementing a custom project and module creation wizard.

This section describes the New Project Wizard API, which is also used to create modules within projects. The page uses "project wizard" wording for brevity.

The New Project wizard items can be grouped into two main types:

Language Project Generators

Language project generators allow for creating general-purpose projects without specific frameworks (they can be added to the project by users later). Examples:

  • a Kotlin project
  • a Python project

These items are displayed at the top in the left sidebar of the New Project dialog.

Language project generators implement LanguageGeneratorNewProjectWizard and are registered in .

The generator implementation must provide:

  • name and icon used in UI
  • ordinal that is used to sort the generator in the generator list
  • isEnabled(WizardContext) that allows controlling displaying the item depending on the current context
  • createStep(NewProjectWizardStep) that creates the tree of steps that users go through during the project creation. Note the provided parent step, which exposes the wizard context, data holder, and other shared properties. See for details.

Examples:

  • KotlinNewProjectWizard generating Kotlin projects
  • PythonNewProjectWizard generating Python projects

Framework Project Generators

Framework project wizards allow for creating projects related to a specific technology, for example:

  • a Spring Boot project
  • a project generated from a Maven Archetype
  • a React project

These items are displayed under language generator items in the left sidebar of the New Project dialog.

Framework project wizards implement GeneratorNewProjectWizard and are registered in .

The interface exposes:

  • unique id
  • name and icon used in UI
  • ordinal that is used to sort the generator in the generator list
  • isEnabled() that allows controlling displaying the item depending on the current IDE context
  • createStep(WizardContext) that creates the tree of steps that users go through during the project creation. See for details.

Example:

  • MavenArchetypeNewProjectWizard creating Maven projects from a selected archetype

Wizard Steps

Every project wizard consists of one or more steps that users go through during project creation. Each step contains UI elements for data necessary to create a project. All the steps are displayed on a single screen in the project wizard dialog, which displays the Create button that creates the project.

Wizards implemented with the old API (ModuleBuilder) can create multiple vertical steps that are navigable with the Next and Previous buttons in the wizard dialog. It caused many screens to be half-empty, and to improve the UX, new wizards display all steps on a single screen.

A project wizard step implements NewProjectWizardStep. The most important methods are:

  • setupUI() - defines the UI components for the step. Step UI is built with .
  • setupProject() - applies the parameters provided in UI to the generated project.

Steps build a tree structure (read the rest of this section for details), as some steps can be displayed depending on previously selected options. setupUI() and setupProject() of steps building the tree are applied in the order from root to leaf. Note that setupProject() won't be called for hidden steps.

For convenience, the platform provides AbstractNewProjectWizardStep, which is a base step class that takes a parent step and delegates common property accessors to the parent. It allows sharing the root step's properties by all descendant steps.

As mentioned before, all steps are rendered on a single screen. Merging multiple steps into a chain displayed as a single screen step is achieved with NewProjectWizardChainStep. Its companion object exposes a helper method NewProjectWizardChainStep.nextStep(), which allows chaining steps in fluent form.

Root Step

The root project wizard step initializes a data holder and other properties shared with all descendant steps in the wizard.

In the case of language project generators, the LanguageGeneratorNewProjectWizard.createStep(NewProjectWizardStep) receives a parent step, and there is no need to initialize these values and create a root step.

In the case of framework project generators, the root step can be created with RootNewProjectWizardStep, which initializes shared properties.

Common Steps

Almost every project requires providing the project name and the location where it should be created. Also, projects are often shared in a Git repository. The IntelliJ Platform provides:

  • NewProjectWizardBaseStep, which handles the project Name and Location fields
  • GitNewProjectWizardStep, which is responsible for handling Git repository initialization if the user enables it

Note that language project generators already include these steps out of the box, and there is no need to create them in the wizard implementation.

Asset Steps

It is often required to populate a created project with initial assets like:

  • directory structure, for example, src/main/java, src/main/resources, src/test/java, src/test/resources in a Gradle Java project
  • a build-tool-specific .gitignore file ignoring build and other directories and files
  • sample code

This can be achieved by creating a step extending AssetsNewProjectWizardStep. See example implementations in the intellij-community repository.

Note that AssetsNewProjectWizardStep requires a dependency on the Java plugin. In addition, it is marked as an experimental API.

{style=warning}

Steps Forking the Wizard Flow

Sometimes, a wizard requires displaying different options depending on the user's selection. For example, depending on the selected build tool, different fields specific to the selected build tool are displayed.

Such a behavior can be implemented with AbstractNewProjectWizardMultiStep.

AbstractNewProjectWizardMultiStep internally handles steps forking the wizard flow. It is responsible for:

  • setting up the switcher
  • setting up the selected step's UI
  • applying the selected step's options to the created project

Forking steps are provided with an extension point implementing NewProjectWizardMultiStepFactory. Besides the parent step, AbstractNewProjectWizardMultiStep's constructor receives the name of the extension point implementing NewProjectWizardMultiStepFactory and uses registered extensions to create steps.

Note that a plugin must implement a custom extension point, which may allow for adding new forking steps (for example, build tools) supported by other plugins.

The section lists example implementations of AbstractNewProjectWizardMultiStep.

Sharing Data Between Steps

Project wizards with multiple steps may require sharing data between them. The recommended approach includes the following implementation steps:

  1. Create an interface exposing step's shared properties, for example, ExampleData:

    interface ExampleData {
      val prop: String
    }
    
  2. Create a companion object with the data key and a helper NewProjectWizardStep.exampleData property.

    interface ExampleData {
      val prop: Boolean
    
      companion object {
        val KEY: Key<ExampleData> = Key.create(ExampleData::class.java.name)
        @JvmStatic
        val NewProjectWizardStep.exampleData: ExampleData?
         get() = data.getUserData(KEY)
      }
    }
    
  3. Make the step implement the created interface (see for implementation details) and implement the data property:

    class ExampleStep(parent: NewProjectWizardStep) :
      AbstractNewProjectWizardStep(parent), ExampleData {
      override val prop = propertyGraph.property(false)
      // ...
    }
    
  4. During step instance initialization, store data in the data holder shared with all steps:

    class ExampleStep(parent: NewProjectWizardStep) :
      AbstractNewProjectWizardStep(parent), ExampleData {
      // ...
      init {
        data.putUserData(ExampleData.KEY, this)
      }
    }
    

Shared data can be accessed in another step in the following way:

class AnotherStep(parent: NewProjectWizardStep) :
   AbstractNewProjectWizardStep(parent) {

   override fun setupProject(project: Project) {
     // exampleData is available via this
     if (exampleData?.prop == true) {
       doSomething()
     }
     // ...
   }
   // ...
}

Property Graph

Persisting Default Settings

It is convenient for users to remember commonly used settings, so they don't need to fill them again. Consider the checkbox initializing a Git repository in a created project. When the user selects it for the first time, and later they create another project, the checkbox will be automatically selected.

This behavior can be implemented by binding properties to storage via methods from BindUtil, for example:

private val gitProperty = propertyGraph.property(false)
    .bindBooleanStorage(GIT_PROPERTY_NAME)

Under the hood, properties are stored at the application level via PropertiesComponent.

Adding Support for Custom Build Systems in Language Project Wizards

Some language project generators contain the Build system field that allows for choosing a build system used by a project. It is possible to add support for custom build systems by extensions dedicated for specific languages. The table below shows the supported languages with corresponding interfaces and extension points:

Language Interface and Extension Point Examples
Java BuildSystemJavaNewProjectWizard
IntelliJJavaNewProjectWizard
MavenJavaNewProjectWizard
GradleJavaNewProjectWizard
Kotlin BuildSystemKotlinNewProjectWizard
IntelliJKotlinNewProjectWizard
MavenKotlinNewProjectWizard
GradleKotlinNewProjectWizard
Groovy BuildSystemGroovyNewProjectWizard
IntelliJGroovyNewProjectWizard
MavenGroovyNewProjectWizard
GradleGroovyNewProjectWizard

Example Project Wizard Steps Structure

The following diagram presents steps of the Kotlin language project wizard implemented by KotlinNewProjectWizard.

Despite being a language generator project wizard, its root step is created by the platform under the hood.

FAQ

How to determine whether the current context is a project or a module creation?

Use WizardContext.isCreatingNewProject(). The wizard context is available in every step via NewProjectWizardStep.context.

How to add a project wizard hint?

Sometimes, a project wizard requires an explanation about the purpose of the wizard or links to an alternative item. To add a simple comment, use CommentNewProjectWizardStep, for example, EmptyProjectGeneratorNewProjectWizard.CommentStep

To additionally render a clickable link to another wizard, use LinkNewProjectWizardStep, for example, MavenArchetypeNewProjectWizard.CommentStep.

What is the status of com.intellij.moduleBuilder?

The ModuleBuilder API is still supported but is not recommended to use in new projects.