1+ /*
2+ * Copyright 2025 The Chromium Authors. All rights reserved.
3+ * Use of this source code is governed by a BSD-style license that can be
4+ * found in the LICENSE file.
5+ */
6+ package io.flutter.project
7+
8+ import com.intellij.openapi.project.Project
9+ import com.intellij.openapi.vfs.VirtualFile
10+ import com.intellij.projectImport.ProjectOpenProcessor
11+ import icons.FlutterIcons
12+ import io.flutter.FlutterBundle
13+ import io.flutter.FlutterUtils
14+ import io.flutter.pub.PubRoot
15+ import io.flutter.utils.FlutterModuleUtils
16+ import java.util.*
17+ import javax.swing.Icon
18+
19+ /* *
20+ * Originally `FlutterProjectOpenProcessor.java`.
21+ *
22+ * This processor handles opening Flutter projects when they are selected directly (e.g. via "Open" in the IDE).
23+ * It delegates the actual opening to the platform's default processor (e.g. Gradle or Maven processor if applicable,
24+ * or the generic project opener) and then ensures that any modules in the project are correctly configured as Flutter modules.
25+ *
26+ * Converted to Kotlin to support `openProjectAsync` which is a suspend function.
27+ */
28+ open class FlutterProjectOpenProcessor : ProjectOpenProcessor () {
29+ override val name: String
30+ get() = FlutterBundle .message(" flutter.module.name" )
31+
32+ override fun getIcon (file : VirtualFile ): Icon ? {
33+ return FlutterIcons .Flutter
34+ }
35+
36+ override fun canOpenProject (file : VirtualFile ): Boolean {
37+ if (FlutterUtils .isAndroidStudio()) {
38+ return false
39+ }
40+ val root = PubRoot .forDirectory(file)
41+ return root != null && root.declaresFlutter()
42+ }
43+
44+ /* *
45+ * Replaces the deprecated `doOpenProject`.
46+ *
47+ * This method is `suspend` and must be used instead of `doOpenProject` to avoid `IllegalStateException` in newer IDE versions.
48+ *
49+ * It performs the following steps:
50+ * 1. Finds a delegate processor (e.g. Gradle) to open the project.
51+ * 2. Opens the project asynchronously.
52+ * 3. Once opened, checks if the project contains Flutter modules that are not yet configured as such (e.g. missing module type).
53+ * 4. Configures these modules as Flutter modules within a write action.
54+ */
55+ override suspend fun openProjectAsync (
56+ virtualFile : VirtualFile ,
57+ projectToClose : Project ? ,
58+ forceOpenInNewFrame : Boolean ,
59+ ): Project ? {
60+ // Delegate opening to the platform open processor.
61+ val importProvider = getDelegateImportProvider(virtualFile) ? : return null
62+ val project = importProvider.openProjectAsync(virtualFile, projectToClose, forceOpenInNewFrame)
63+ if (project == null || project.isDisposed) return project
64+
65+ // Convert any modules that use Flutter but don't have IntelliJ Flutter metadata.
66+ convertToFlutterProject(project)
67+
68+ return project
69+ }
70+
71+ /* *
72+ * Deprecated method, kept to satisfy the compiler/interface.
73+ *
74+ * We return `null` to indicate that this processor does not support the synchronous opening method
75+ * and that `openProjectAsync` should be used instead.
76+ */
77+ override fun doOpenProject (
78+ virtualFile : VirtualFile ,
79+ projectToClose : Project ? ,
80+ forceOpenInNewFrame : Boolean ,
81+ ): Project ? {
82+ return null
83+ }
84+
85+ protected open fun getDelegateImportProvider (file : VirtualFile ): ProjectOpenProcessor ? {
86+ return EXTENSION_POINT_NAME .extensionList.stream().filter { processor: ProjectOpenProcessor ->
87+ processor.canOpenProject(file) && ! Objects .equals(
88+ processor.name,
89+ name
90+ )
91+ }.findFirst().orElse(null )
92+ }
93+ }
94+
95+ /* *
96+ * Sets up a project that doesn't have any Flutter modules.
97+ *
98+ *
99+ * (It probably wasn't created with "flutter create" and probably didn't have any IntelliJ configuration before.)
100+ */
101+ private fun convertToFlutterProject (project : Project ) {
102+ for (module in FlutterModuleUtils .getModules(project)) {
103+ if (FlutterModuleUtils .declaresFlutter(module) && ! FlutterModuleUtils .isFlutterModule(module)) {
104+ FlutterModuleUtils .setFlutterModuleAndReload(module, project)
105+ }
106+ }
107+ }
0 commit comments