@Override
  protected void processData(
      @NotNull final Collection<DataNode<ModuleData>> nodes, @NotNull Project project) {
    if (nodes.isEmpty()) {
      return;
    }
    ProjectSystemId externalSystemId = nodes.iterator().next().getData().getOwner();
    ExternalSystemManager<?, ?, ?, ?, ?> manager =
        ExternalSystemApiUtil.getManager(externalSystemId);
    assert manager != null;

    final MultiMap<DataNode<ProjectData>, DataNode<ModuleData>> grouped =
        ExternalSystemApiUtil.groupBy(nodes, ProjectKeys.PROJECT);
    Map<ExternalProjectPojo, Collection<ExternalProjectPojo>> data = ContainerUtilRt.newHashMap();
    for (Map.Entry<DataNode<ProjectData>, Collection<DataNode<ModuleData>>> entry :
        grouped.entrySet()) {
      data.put(
          ExternalProjectPojo.from(entry.getKey().getData()),
          ContainerUtilRt.map2List(entry.getValue(), MAPPER));
    }

    AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project);
    Set<String> pathsToForget = detectRenamedProjects(data, settings.getAvailableProjects());
    if (!pathsToForget.isEmpty()) {
      settings.forgetExternalProjects(pathsToForget);
    }
    Map<ExternalProjectPojo, Collection<ExternalProjectPojo>> projects =
        ContainerUtilRt.newHashMap(settings.getAvailableProjects());
    projects.putAll(data);
    settings.setAvailableProjects(projects);
  }
  @Nullable
  protected String resolveProjectPath(@NotNull Module module) {
    final String rootProjectPath = ExternalSystemApiUtil.getExternalRootProjectPath(module);
    String projectPath = ExternalSystemApiUtil.getExternalProjectPath(module);

    if (rootProjectPath == null || projectPath == null) return null;
    if (!FileUtil.isAncestor(rootProjectPath, projectPath, false)) {
      projectPath = rootProjectPath;
    }
    return projectPath;
  }
  private static void addModuleNodes(
      @NotNull ExternalProjectsView externalProjectsView,
      @NotNull MultiMap<Key<?>, DataNode<?>> dataNodes,
      @NotNull List<ExternalSystemNode<?>> result) {
    final Collection<DataNode<?>> moduleDataNodes = dataNodes.get(ProjectKeys.MODULE);
    if (!moduleDataNodes.isEmpty()) {
      final AbstractExternalSystemSettings systemSettings =
          ExternalSystemApiUtil.getSettings(
              externalProjectsView.getProject(), externalProjectsView.getSystemId());

      for (DataNode<?> dataNode : moduleDataNodes) {
        final ModuleData data = (ModuleData) dataNode.getData();

        final ExternalProjectSettings projectSettings =
            systemSettings.getLinkedProjectSettings(data.getLinkedExternalProjectPath());
        final boolean isRoot =
            projectSettings != null
                && data.getLinkedExternalProjectPath()
                    .equals(projectSettings.getExternalProjectPath());
        //noinspection unchecked
        final ModuleNode moduleNode =
            new ModuleNode(externalProjectsView, (DataNode<ModuleData>) dataNode, isRoot);
        result.add(moduleNode);
      }
    }
  }
  @Override
  public void setupRootModel(final ModifiableRootModel modifiableRootModel)
      throws ConfigurationException {
    String contentEntryPath = getContentEntryPath();
    if (StringUtil.isEmpty(contentEntryPath)) {
      return;
    }
    File contentRootDir = new File(contentEntryPath);
    FileUtilRt.createDirectory(contentRootDir);
    LocalFileSystem fileSystem = LocalFileSystem.getInstance();
    VirtualFile modelContentRootDir = fileSystem.refreshAndFindFileByIoFile(contentRootDir);
    if (modelContentRootDir == null) {
      return;
    }

    modifiableRootModel.addContentEntry(modelContentRootDir);
    modifiableRootModel.inheritSdk();

    final Project project = modifiableRootModel.getProject();

    setupGradleBuildFile(modelContentRootDir);
    setupGradleSettingsFile(modelContentRootDir, modifiableRootModel);

    if (myWizardContext.isCreatingNewProject()) {
      String externalProjectPath = FileUtil.toCanonicalPath(project.getBasePath());
      getExternalProjectSettings().setExternalProjectPath(externalProjectPath);
      AbstractExternalSystemSettings settings =
          ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID);
      //noinspection unchecked
      settings.linkProject(getExternalProjectSettings());
    } else {
      FileDocumentManager.getInstance().saveAllDocuments();
      ExternalSystemUtil.refreshProjects(project, GradleConstants.SYSTEM_ID, false);
    }
  }
  @Override
  protected void processData(
      @NotNull Collection<DataNode<TaskData>> nodes, @NotNull Project project) {
    if (nodes.isEmpty()) {
      return;
    }
    ProjectSystemId externalSystemId = nodes.iterator().next().getData().getOwner();
    ExternalSystemManager<?, ?, ?, ?, ?> manager =
        ExternalSystemApiUtil.getManager(externalSystemId);
    assert manager != null;

    ExternalSystemKeymapExtension.updateActions(project, nodes);

    MultiMap<ExternalConfigPathAware, DataNode<TaskData>> grouped =
        ContainerUtil.groupBy(nodes, TASK_HOLDER_RETRIEVAL_STRATEGY);
    Map<String, Collection<ExternalTaskPojo>> data = ContainerUtilRt.newHashMap();
    for (Map.Entry<ExternalConfigPathAware, Collection<DataNode<TaskData>>> entry :
        grouped.entrySet()) {
      data.put(
          entry.getKey().getLinkedExternalProjectPath(),
          ContainerUtilRt.map2List(entry.getValue(), MAPPER));
    }

    AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project);
    Map<String, Collection<ExternalTaskPojo>> availableTasks =
        ContainerUtilRt.newHashMap(settings.getAvailableTasks());
    availableTasks.putAll(data);
    settings.setAvailableTasks(availableTasks);
  }
 private static boolean hasGradleModules(@NotNull CompileContext context) {
   for (Module module : context.getCompileScope().getAffectedModules()) {
     if (ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module))
       return true;
   }
   return false;
 }
  @SuppressWarnings("unchecked")
  private void executeAndRestoreDefaultProjectSettings(
      @NotNull Project project, @NotNull Runnable task) {
    if (!project.isDefault()) {
      task.run();
      return;
    }

    AbstractExternalSystemSettings systemSettings =
        ExternalSystemApiUtil.getSettings(project, myExternalSystemId);
    Object systemStateToRestore = null;
    if (systemSettings instanceof PersistentStateComponent) {
      systemStateToRestore = ((PersistentStateComponent) systemSettings).getState();
    }
    systemSettings.copyFrom(myControl.getSystemSettings());
    Collection projectSettingsToRestore = systemSettings.getLinkedProjectsSettings();
    systemSettings.setLinkedProjectsSettings(
        Collections.singleton(getCurrentExternalProjectSettings()));
    try {
      task.run();
    } finally {
      if (systemStateToRestore != null) {
        ((PersistentStateComponent) systemSettings).loadState(systemStateToRestore);
      } else {
        systemSettings.setLinkedProjectsSettings(projectSettingsToRestore);
      }
    }
  }
 private void importMissingProjectLibraries(
     @NotNull Module module,
     @NotNull Collection<DataNode<LibraryDependencyData>> nodesToImport,
     boolean synchronous) {
   LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject());
   List<DataNode<LibraryData>> librariesToImport = ContainerUtilRt.newArrayList();
   for (DataNode<LibraryDependencyData> dataNode : nodesToImport) {
     final LibraryDependencyData dependencyData = dataNode.getData();
     if (dependencyData.getLevel() != LibraryLevel.PROJECT) {
       continue;
     }
     final Library library = libraryTable.getLibraryByName(dependencyData.getName());
     if (library == null) {
       DataNode<ProjectData> projectNode = dataNode.getDataNode(ProjectKeys.PROJECT);
       if (projectNode != null) {
         DataNode<LibraryData> libraryNode =
             ExternalSystemApiUtil.find(
                 projectNode,
                 ProjectKeys.LIBRARY,
                 new BooleanFunction<DataNode<LibraryData>>() {
                   @Override
                   public boolean fun(DataNode<LibraryData> node) {
                     return node.getData().equals(dependencyData.getTarget());
                   }
                 });
         if (libraryNode != null) {
           librariesToImport.add(libraryNode);
         }
       }
     }
   }
   if (!librariesToImport.isEmpty()) {
     myLibraryManager.importData(librariesToImport, module.getProject(), synchronous);
   }
 }
  @Override
  public void importData(
      @NotNull Collection<DataNode<LibraryDependencyData>> toImport,
      @NotNull Project project,
      boolean synchronous) {
    if (toImport.isEmpty()) {
      return;
    }

    Map<DataNode<ModuleData>, List<DataNode<LibraryDependencyData>>> byModule =
        ExternalSystemApiUtil.groupBy(toImport, MODULE);
    for (Map.Entry<DataNode<ModuleData>, List<DataNode<LibraryDependencyData>>> entry :
        byModule.entrySet()) {
      Module module = myProjectStructureHelper.findIdeModule(entry.getKey().getData(), project);
      if (module == null) {
        myModuleManager.importData(Collections.singleton(entry.getKey()), project, true);
        module = myProjectStructureHelper.findIdeModule(entry.getKey().getData(), project);
        if (module == null) {
          LOG.warn(
              String.format(
                  "Can't import library dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported",
                  entry.getValue(), entry.getKey()));
          continue;
        }
      }
      importData(entry.getValue(), module, synchronous);
    }
  }
  @Override
  public void importData(
      @NotNull Collection<DataNode<ProjectData>> toImport,
      @Nullable ProjectData projectData,
      @NotNull final Project project,
      @NotNull IdeModifiableModelsProvider modelsProvider) {
    // root project can be marked as ignored
    if (toImport.isEmpty()) return;

    if (toImport.size() != 1) {
      throw new IllegalArgumentException(
          String.format(
              "Expected to get a single project but got %d: %s", toImport.size(), toImport));
    }
    DataNode<ProjectData> node = toImport.iterator().next();
    assert projectData == node.getData();

    if (!ExternalSystemApiUtil.isOneToOneMapping(project, node)) {
      return;
    }

    if (!project.getName().equals(projectData.getInternalName())) {
      renameProject(projectData.getInternalName(), projectData.getOwner(), project);
    }
  }
  @SuppressWarnings("unchecked")
  @Override
  protected void doExecute() throws Exception {
    final ExternalSystemFacadeManager manager =
        ServiceManager.getService(ExternalSystemFacadeManager.class);
    ExternalSystemExecutionSettings settings =
        ExternalSystemApiUtil.getExecutionSettings(
            getIdeProject(), getExternalProjectPath(), getExternalSystemId());
    RemoteExternalSystemFacade facade =
        manager.getFacade(getIdeProject(), getExternalProjectPath(), getExternalSystemId());
    RemoteExternalSystemTaskManager taskManager = facade.getTaskManager();
    List<String> taskNames = ContainerUtilRt.map2List(myTasksToExecute, MAPPER);

    final List<String> vmOptions = parseCmdParameters(myVmOptions);
    final List<String> scriptParametersList = parseCmdParameters(myScriptParameters);

    taskManager.executeTasks(
        getId(),
        taskNames,
        getExternalProjectPath(),
        settings,
        vmOptions,
        scriptParametersList,
        myDebuggerSetup);
  }
 private void syncExistingAndRemoveObsolete(
     @NotNull IdeModifiableModelsProvider modelsProvider,
     @NotNull Map<Set<String>, LibraryDependencyData> moduleLibrariesToImport,
     @NotNull Map<String, LibraryDependencyData> projectLibrariesToImport,
     @NotNull Set<LibraryDependencyData> toImport,
     @NotNull Map<OrderEntry, OrderAware> orderEntryDataMap,
     @NotNull ModifiableRootModel moduleRootModel,
     boolean hasUnresolvedLibraries) {
   for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
     if (entry instanceof ModuleLibraryOrderEntryImpl) {
       ModuleLibraryOrderEntryImpl moduleLibraryOrderEntry = (ModuleLibraryOrderEntryImpl) entry;
       Library library = moduleLibraryOrderEntry.getLibrary();
       if (library == null) {
         LOG.warn(
             "Skipping module-level library entry because it doesn't have backing Library object. Entry: "
                 + entry);
         continue;
       }
       final VirtualFile[] libraryFiles = library.getFiles(OrderRootType.CLASSES);
       final Set<String> moduleLibraryKey = ContainerUtilRt.newHashSet(libraryFiles.length);
       for (VirtualFile file : libraryFiles) {
         moduleLibraryKey.add(
             ExternalSystemApiUtil.getLocalFileSystemPath(file)
                 + moduleLibraryOrderEntry.getScope().name());
       }
       LibraryDependencyData existing = moduleLibrariesToImport.remove(moduleLibraryKey);
       if (existing == null || !StringUtil.equals(existing.getInternalName(), library.getName())) {
         moduleRootModel.removeOrderEntry(entry);
       } else {
         orderEntryDataMap.put(entry, existing);
         syncExistingLibraryDependency(
             modelsProvider,
             existing,
             library,
             moduleRootModel,
             moduleLibraryOrderEntry.getOwnerModule());
         toImport.remove(existing);
       }
     } else if (entry instanceof LibraryOrderEntry) {
       LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) entry;
       String libraryName = libraryOrderEntry.getLibraryName();
       LibraryDependencyData existing =
           projectLibrariesToImport.remove(libraryName + libraryOrderEntry.getScope().name());
       if (existing != null) {
         toImport.remove(existing);
         orderEntryDataMap.put(entry, existing);
       } else if (!hasUnresolvedLibraries) {
         // There is a possible case that a project has been successfully imported from external
         // model and after
         // that network/repo goes down. We don't want to drop existing binary mappings then.
         moduleRootModel.removeOrderEntry(entry);
       }
     }
   }
 }
 @Override
 protected boolean isApplicableFor(@NotNull RunConfigurationBase configuration) {
   if (configuration instanceof ModuleBasedConfiguration
       && configuration instanceof CommonProgramRunConfigurationParameters) {
     final RunConfigurationModule runConfigurationModule =
         ((ModuleBasedConfiguration) configuration).getConfigurationModule();
     return ExternalSystemApiUtil.isExternalSystemAwareModule(
         GradleConstants.SYSTEM_ID, runConfigurationModule.getModule());
   }
   return false;
 }
  @Override
  public void setupRootModel(ModifiableRootModel model) throws ConfigurationException {
    String contentPath = getContentEntryPath();
    if (StringUtil.isEmpty(contentPath)) {
      return;
    }
    File contentRootDir = new File(contentPath);
    FileUtilRt.createDirectory(contentRootDir);
    LocalFileSystem fileSystem = LocalFileSystem.getInstance();
    VirtualFile vContentRootDir = fileSystem.refreshAndFindFileByIoFile(contentRootDir);
    if (vContentRootDir == null) {
      return;
    }

    model.addContentEntry(vContentRootDir);

    VirtualFile configFile = getExternalProjectConfigFile(vContentRootDir);
    if (configFile != null && myTemplateConfigName != null) {
      FileTemplateManager manager = FileTemplateManager.getInstance();
      FileTemplate template = manager.getInternalTemplate(myTemplateConfigName);
      try {
        VfsUtil.saveText(configFile, template.getText());
      } catch (IOException e) {
        LOG.warn(
            String.format(
                "Unexpected exception on applying template %s config",
                myExternalSystemId.getReadableName()),
            e);
        throw new ConfigurationException(
            e.getMessage(),
            String.format(
                "Can't apply %s template config text", myExternalSystemId.getReadableName()));
      }
    }

    AbstractExternalSystemSettings settings =
        ExternalSystemApiUtil.getSettings(model.getProject(), myExternalSystemId);
    S externalProjectSettings = createSettings();
    if (myExternalProjectSettingsControl != null) {
      String errorMessage = myExternalProjectSettingsControl.apply(externalProjectSettings);
      myExternalProjectSettingsControl.disposeUIResources();
      if (errorMessage != null) {
        throw new ConfigurationException(errorMessage);
      }
    }
    //noinspection unchecked
    settings.linkProject(externalProjectSettings);
  }
  /**
   * The whole import sequence looks like below:
   *
   * <p>
   *
   * <pre>
   * <ol>
   *   <li>Get project view from the gradle tooling api without resolving dependencies (downloading libraries);</li>
   *   <li>Allow to adjust project settings before importing;</li>
   *   <li>Create IJ project and modules;</li>
   *   <li>Ask gradle tooling api to resolve library dependencies (download the if necessary);</li>
   *   <li>Configure libraries used by the gradle project at intellij;</li>
   *   <li>Configure library dependencies;</li>
   * </ol>
   * </pre>
   *
   * <p>
   *
   * @param projectWithResolvedLibraries gradle project with resolved libraries (libraries have
   *     already been downloaded and are available at file system under gradle service directory)
   * @param project current intellij project which should be configured by libraries and module
   *     library dependencies information available at the given gradle project
   */
  private void setupLibraries(
      @NotNull final DataNode<ProjectData> projectWithResolvedLibraries, final Project project) {
    ExternalSystemApiUtil.executeProjectChangeAction(
        new DisposeAwareProjectChange(project) {
          @Override
          public void execute() {
            ProjectRootManagerEx.getInstanceEx(project)
                .mergeRootsChangesDuring(
                    new Runnable() {
                      @Override
                      public void run() {
                        if (ExternalSystemApiUtil.isNewProjectConstruction()) {
                          // Clean existing libraries (if any).
                          LibraryTable projectLibraryTable =
                              ProjectLibraryTable.getInstance(project);
                          if (projectLibraryTable == null) {
                            LOG.warn(
                                "Can't resolve external dependencies of the target gradle project ("
                                    + project
                                    + "). Reason: project "
                                    + "library table is undefined");
                            return;
                          }
                          LibraryTable.ModifiableModel model =
                              projectLibraryTable.getModifiableModel();
                          try {
                            for (Library library : model.getLibraries()) {
                              model.removeLibrary(library);
                            }
                          } finally {
                            model.commit();
                          }
                        }

                        // Register libraries.
                        Set<DataNode<?>> toImport = ContainerUtilRt.newHashSet();
                        toImport.add(projectWithResolvedLibraries);
                        myProjectDataManager.importData(toImport, project, false);
                      }
                    });
          }
        });
  }
 @Override
 protected void validateConfiguration(
     @NotNull RunConfigurationBase configuration, boolean isExecution) throws Exception {
   super.validateConfiguration(configuration, isExecution);
   if (configuration instanceof ModuleBasedConfiguration
       && configuration instanceof CommonProgramRunConfigurationParameters) {
     final String workingDirectory =
         ((CommonProgramRunConfigurationParameters) configuration).getWorkingDirectory();
     if (("$" + PathMacroUtil.MODULE_DIR_MACRO_NAME + "$").equals(workingDirectory)) {
       final RunConfigurationModule runConfigurationModule =
           ((ModuleBasedConfiguration) configuration).getConfigurationModule();
       final String projectPath =
           ExternalSystemApiUtil.getExternalProjectPath(runConfigurationModule.getModule());
       if (StringUtil.isNotEmpty(projectPath)) {
         ((CommonProgramRunConfigurationParameters) configuration)
             .setWorkingDirectory(projectPath);
       }
     }
   }
 }
 private static void createActions(Project project, Collection<DataNode<TaskData>> taskNodes) {
   ActionManager actionManager = ActionManager.getInstance();
   final ExternalSystemShortcutsManager shortcutsManager =
       ExternalProjectsManager.getInstance(project).getShortcutsManager();
   if (actionManager != null) {
     for (DataNode<TaskData> each : taskNodes) {
       final DataNode<ModuleData> moduleData =
           ExternalSystemApiUtil.findParent(each, ProjectKeys.MODULE);
       if (moduleData == null || moduleData.isIgnored()) continue;
       TaskData taskData = each.getData();
       ExternalSystemTaskAction eachAction =
           new ExternalSystemTaskAction(project, moduleData.getData().getInternalName(), taskData);
       actionManager.unregisterAction(eachAction.getId());
       if (shortcutsManager.hasShortcuts(
           taskData.getLinkedExternalProjectPath(), taskData.getName())) {
         actionManager.registerAction(eachAction.getId(), eachAction);
       }
     }
   }
 }
 private static void renameProject(
     @NotNull final String newName,
     @NotNull final ProjectSystemId externalSystemId,
     @NotNull final Project project) {
   if (!(project instanceof ProjectEx) || newName.equals(project.getName())) {
     return;
   }
   ExternalSystemApiUtil.executeProjectChangeAction(
       true,
       new DisposeAwareProjectChange(project) {
         @Override
         public void execute() {
           String oldName = project.getName();
           ((ProjectEx) project).setProjectName(newName);
           ExternalSystemApiUtil.getSettings(project, externalSystemId)
               .getPublisher()
               .onProjectRenamed(oldName, newName);
         }
       });
 }
 @Override
 public void importData(
     @NotNull Collection<DataNode<ModuleDependencyData>> toImport,
     @Nullable ProjectData projectData,
     @NotNull Project project,
     @NotNull PlatformFacade platformFacade,
     boolean synchronous) {
   MultiMap<DataNode<ModuleData>, DataNode<ModuleDependencyData>> byModule =
       ExternalSystemApiUtil.groupBy(toImport, MODULE);
   for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<ModuleDependencyData>>> entry :
       byModule.entrySet()) {
     Module ideModule = platformFacade.findIdeModule(entry.getKey().getData(), project);
     if (ideModule == null) {
       LOG.warn(
           String.format(
               "Can't import module dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported",
               entry.getValue(), entry.getKey()));
       continue;
     }
     importData(entry.getValue(), ideModule, platformFacade, synchronous);
   }
 }
 private static void removeObsolete(
     @NotNull Map<Set<String>, LibraryDependencyData> moduleLibrariesToImport,
     @NotNull Map<String, LibraryDependencyData> projectLibrariesToImport,
     @NotNull Set<LibraryDependencyData> toImport,
     @NotNull ModifiableRootModel moduleRootModel) {
   Set<String> moduleLibraryKey = ContainerUtilRt.newHashSet();
   for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
     if (entry instanceof ModuleLibraryOrderEntryImpl) {
       Library library = ((ModuleLibraryOrderEntryImpl) entry).getLibrary();
       if (library == null) {
         LOG.warn(
             "Skipping module-level library entry because it doesn't have backing Library object. Entry: "
                 + entry);
         continue;
       }
       moduleLibraryKey.clear();
       for (VirtualFile file : library.getFiles(OrderRootType.CLASSES)) {
         moduleLibraryKey.add(ExternalSystemApiUtil.getLocalFileSystemPath(file));
       }
       LibraryDependencyData existing = moduleLibrariesToImport.remove(moduleLibraryKey);
       if (existing == null) {
         moduleRootModel.removeOrderEntry(entry);
       } else {
         toImport.remove(existing);
       }
     } else if (entry instanceof LibraryOrderEntry) {
       String libraryName = ((LibraryOrderEntry) entry).getLibraryName();
       LibraryDependencyData existing = projectLibrariesToImport.remove(libraryName);
       if (existing == null) {
         moduleRootModel.removeOrderEntry(entry);
       } else {
         toImport.remove(existing);
       }
     }
   }
 }
  @Override
  public void importData(
      @NotNull final Collection<DataNode<BuildScriptClasspathData>> toImport,
      @NotNull final Project project,
      boolean synchronous) {
    if (toImport.isEmpty()) {
      return;
    }
    if (!project.isInitialized()) {
      return;
    }

    final GradleInstallationManager gradleInstallationManager =
        ServiceManager.getService(GradleInstallationManager.class);

    ExternalSystemManager<?, ?, ?, ?, ?> manager =
        ExternalSystemApiUtil.getManager(GradleConstants.SYSTEM_ID);
    assert manager != null;
    AbstractExternalSystemLocalSettings localSettings =
        manager.getLocalSettingsProvider().fun(project);

    //noinspection MismatchedQueryAndUpdateOfCollection
    Map<String /* externalProjectPath */, Set<String>> externalProjectGradleSdkLibs =
        new FactoryMap<String, Set<String>>() {
          @Nullable
          @Override
          protected Set<String> create(String externalProjectPath) {
            GradleProjectSettings settings =
                GradleSettings.getInstance(project).getLinkedProjectSettings(externalProjectPath);
            if (settings == null || settings.getDistributionType() == null) return null;

            final Set<String> gradleSdkLibraries = ContainerUtil.newLinkedHashSet();
            File gradleHome =
                gradleInstallationManager.getGradleHome(
                    settings.getDistributionType(), externalProjectPath, settings.getGradleHome());
            if (gradleHome != null && gradleHome.isDirectory()) {

              final Collection<File> libraries =
                  gradleInstallationManager.getClassRoots(project, externalProjectPath);
              if (libraries != null) {
                for (File library : libraries) {
                  gradleSdkLibraries.add(FileUtil.toCanonicalPath(library.getPath()));
                }
              }
            }
            return gradleSdkLibraries;
          }
        };

    for (final DataNode<BuildScriptClasspathData> node : toImport) {
      if (GradleConstants.SYSTEM_ID.equals(node.getData().getOwner())) {

        DataNode<ProjectData> projectDataNode =
            ExternalSystemApiUtil.findParent(node, ProjectKeys.PROJECT);
        assert projectDataNode != null;

        String linkedExternalProjectPath = projectDataNode.getData().getLinkedExternalProjectPath();
        DataNode<ModuleData> moduleDataNode =
            ExternalSystemApiUtil.findParent(node, ProjectKeys.MODULE);
        if (moduleDataNode == null) continue;

        String externalModulePath = moduleDataNode.getData().getLinkedExternalProjectPath();
        GradleProjectSettings settings =
            GradleSettings.getInstance(project).getLinkedProjectSettings(linkedExternalProjectPath);
        if (settings == null || settings.getDistributionType() == null) continue;

        final Set<String> buildClasspath = ContainerUtil.newLinkedHashSet();
        BuildScriptClasspathData buildScriptClasspathData = node.getData();
        for (BuildScriptClasspathData.ClasspathEntry classpathEntry :
            buildScriptClasspathData.getClasspathEntries()) {
          for (String path : classpathEntry.getSourcesFile()) {
            buildClasspath.add(FileUtil.toCanonicalPath(path));
          }

          for (String path : classpathEntry.getClassesFile()) {
            buildClasspath.add(FileUtil.toCanonicalPath(path));
          }
        }

        ExternalProjectBuildClasspathPojo projectBuildClasspathPojo =
            localSettings.getProjectBuildClasspath().get(linkedExternalProjectPath);
        if (projectBuildClasspathPojo == null) {
          projectBuildClasspathPojo =
              new ExternalProjectBuildClasspathPojo(
                  moduleDataNode.getData().getExternalName(),
                  ContainerUtil.<String>newArrayList(),
                  ContainerUtil.<String, ExternalModuleBuildClasspathPojo>newHashMap());
          localSettings
              .getProjectBuildClasspath()
              .put(linkedExternalProjectPath, projectBuildClasspathPojo);
        }

        List<String> projectBuildClasspath =
            ContainerUtil.newArrayList(externalProjectGradleSdkLibs.get(linkedExternalProjectPath));
        // add main java root of buildSrc project
        projectBuildClasspath.add(linkedExternalProjectPath + "/buildSrc/src/main/java");
        // add main groovy root of buildSrc project
        projectBuildClasspath.add(linkedExternalProjectPath + "/buildSrc/src/main/groovy");

        projectBuildClasspathPojo.setProjectBuildClasspath(projectBuildClasspath);
        projectBuildClasspathPojo
            .getModulesBuildClasspath()
            .put(
                externalModulePath,
                new ExternalModuleBuildClasspathPojo(
                    externalModulePath, ContainerUtil.newArrayList(buildClasspath)));
      }
    }

    GradleBuildClasspathManager.getInstance(project).reload();
  }
  @NotNull
  static List<String> getTasksToRun(Module module) {
    final List<String> result;
    final String externalProjectId = ExternalSystemApiUtil.getExternalProjectId(module);
    if (externalProjectId == null) return ContainerUtil.emptyList();
    final String projectPath = ExternalSystemApiUtil.getExternalProjectPath(module);
    if (projectPath == null) return ContainerUtil.emptyList();
    final ExternalProjectInfo externalProjectInfo =
        ExternalSystemUtil.getExternalProjectInfo(
            module.getProject(), GradleConstants.SYSTEM_ID, projectPath);
    if (externalProjectInfo == null) return ContainerUtil.emptyList();

    if (StringUtil.endsWith(externalProjectId, ":test")
        || StringUtil.endsWith(externalProjectId, ":main")) {
      result = TEST_SOURCE_SET_TASKS;
    } else {
      final DataNode<ModuleData> moduleNode =
          GradleProjectResolverUtil.findModule(
              externalProjectInfo.getExternalProjectStructure(), projectPath);
      if (moduleNode == null) return ContainerUtil.emptyList();
      final String sourceSetId =
          StringUtil.substringAfter(
              externalProjectId, moduleNode.getData().getExternalName() + ':');
      if (sourceSetId == null) return ContainerUtil.emptyList();

      final DataNode<TaskData> taskNode =
          ExternalSystemApiUtil.find(
              moduleNode,
              ProjectKeys.TASK,
              new BooleanFunction<DataNode<TaskData>>() {
                @Override
                public boolean fun(DataNode<TaskData> node) {
                  return GradleCommonClassNames.GRADLE_API_TASKS_TESTING_TEST.equals(
                          node.getData().getType())
                      && StringUtil.startsWith(sourceSetId, node.getData().getName());
                }
              });

      if (taskNode == null) return ContainerUtil.emptyList();
      final String taskName = taskNode.getData().getName();
      result = ContainerUtil.list("clean" + StringUtil.capitalize(taskName), taskName);
    }

    final String path;
    if (!externalProjectId.startsWith(":")) {
      path = ":";
    } else {
      final List<String> pathParts = StringUtil.split(externalProjectId, ":");
      if (!pathParts.isEmpty()) pathParts.remove(pathParts.size() - 1);
      final String join = StringUtil.join(pathParts, ":");
      path = ":" + join + (!join.isEmpty() ? ":" : "");
    }
    return ContainerUtil.map(
        result,
        new Function<String, String>() {
          @Override
          public String fun(String s) {
            return path + s;
          }
        });
  }
  @Override
  protected Map<OrderEntry, OrderAware> importData(
      @NotNull final Collection<DataNode<LibraryDependencyData>> nodesToImport,
      @NotNull final Module module,
      @NotNull final IdeModifiableModelsProvider modelsProvider) {
    // The general idea is to import all external project library dependencies and module libraries
    // which don't present at the
    // ide side yet and remove all project library dependencies and module libraries which present
    // at the ide but not at
    // the given collection.
    // The trick is that we should perform module settings modification inside try/finally block
    // against target root model.
    // That means that we need to prepare all necessary data, obtain a model and modify it as
    // necessary.
    final Map<Set<String> /* library paths */, LibraryDependencyData> moduleLibrariesToImport =
        ContainerUtilRt.newHashMap();
    final Map<String /* library name + scope */, LibraryDependencyData> projectLibrariesToImport =
        ContainerUtilRt.newHashMap();
    final Set<LibraryDependencyData> toImport = ContainerUtilRt.newLinkedHashSet();
    final Map<OrderEntry, OrderAware> orderEntryDataMap = ContainerUtil.newLinkedHashMap();

    boolean hasUnresolved = false;
    for (DataNode<LibraryDependencyData> dependencyNode : nodesToImport) {
      LibraryDependencyData dependencyData = dependencyNode.getData();
      LibraryData libraryData = dependencyData.getTarget();
      hasUnresolved |= libraryData.isUnresolved();
      switch (dependencyData.getLevel()) {
        case MODULE:
          Set<String> paths = ContainerUtilRt.newHashSet();
          for (String path : libraryData.getPaths(LibraryPathType.BINARY)) {
            paths.add(
                ExternalSystemApiUtil.toCanonicalPath(path) + dependencyData.getScope().name());
          }
          moduleLibrariesToImport.put(paths, dependencyData);
          toImport.add(dependencyData);
          break;
        case PROJECT:
          projectLibrariesToImport.put(
              libraryData.getInternalName() + dependencyData.getScope().name(), dependencyData);
          toImport.add(dependencyData);
      }
    }

    final boolean finalHasUnresolved = hasUnresolved;

    final ModifiableRootModel modifiableRootModel = modelsProvider.getModifiableRootModel(module);
    LibraryTable moduleLibraryTable = modifiableRootModel.getModuleLibraryTable();
    syncExistingAndRemoveObsolete(
        modelsProvider,
        moduleLibrariesToImport,
        projectLibrariesToImport,
        toImport,
        orderEntryDataMap,
        modifiableRootModel,
        finalHasUnresolved);
    // Import missing library dependencies.
    if (!toImport.isEmpty()) {
      importMissing(
          modelsProvider,
          toImport,
          orderEntryDataMap,
          modifiableRootModel,
          moduleLibraryTable,
          module);
    }
    return orderEntryDataMap;
  }
  @NotNull
  private DataNode<ProjectData> doResolveProjectInfo(
      @NotNull final ProjectResolverContext resolverCtx,
      @NotNull final GradleProjectResolverExtension projectResolverChain)
      throws IllegalArgumentException, IllegalStateException {

    final ProjectImportAction projectImportAction =
        new ProjectImportAction(resolverCtx.isPreviewMode());

    // inject ProjectResolverContext into gradle project resolver extensions
    // collect extra JVM arguments provided by gradle project resolver extensions
    // and register classes of extra gradle project models required for extensions (e.g.
    // com.android.builder.model.AndroidProject)
    final List<KeyValue<String, String>> extraJvmArgs = new ArrayList<KeyValue<String, String>>();
    for (GradleProjectResolverExtension resolverExtension = projectResolverChain;
        resolverExtension != null;
        resolverExtension = resolverExtension.getNext()) {
      resolverExtension.setProjectResolverContext(resolverCtx);
      projectImportAction.addExtraProjectModelClasses(
          resolverExtension.getExtraProjectModelClasses());
      extraJvmArgs.addAll(resolverExtension.getExtraJvmArgs());
    }
    final ParametersList parametersList = new ParametersList();
    for (KeyValue<String, String> jvmArg : extraJvmArgs) {
      parametersList.addProperty(jvmArg.getKey(), jvmArg.getValue());
    }

    BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor =
        resolverCtx.getConnection().action(projectImportAction);
    GradleExecutionHelper.prepare(
        buildActionExecutor,
        resolverCtx.getExternalSystemTaskId(),
        resolverCtx.getSettings(),
        resolverCtx.getListener(),
        parametersList.getParameters(),
        resolverCtx.getConnection());

    // TODO [vlad] remove the check
    if (GradleEnvironment.USE_ENHANCED_TOOLING_API) {
      GradleExecutionHelper.setInitScript(buildActionExecutor);
    }

    ProjectImportAction.AllModels allModels;
    try {
      allModels = buildActionExecutor.run();
      if (allModels == null) {
        throw new IllegalStateException(
            "Unable to get project model for the project: " + resolverCtx.getProjectPath());
      }
    } catch (UnsupportedVersionException unsupportedVersionException) {
      // Old gradle distribution version used (before ver. 1.8)
      // fallback to use ModelBuilder gradle tooling API
      ModelBuilder<? extends IdeaProject> modelBuilder =
          myHelper.getModelBuilder(
              resolverCtx.isPreviewMode() ? BasicIdeaProject.class : IdeaProject.class,
              resolverCtx.getExternalSystemTaskId(),
              resolverCtx.getSettings(),
              resolverCtx.getConnection(),
              resolverCtx.getListener(),
              parametersList.getParameters());

      final IdeaProject ideaProject = modelBuilder.get();
      allModels = new ProjectImportAction.AllModels(ideaProject);
    }

    final BuildEnvironment buildEnvironment = getBuildEnvironment(resolverCtx);
    allModels.setBuildEnvironment(buildEnvironment);
    resolverCtx.setModels(allModels);

    // import project data
    ProjectData projectData = projectResolverChain.createProject();
    DataNode<ProjectData> projectDataNode =
        new DataNode<ProjectData>(ProjectKeys.PROJECT, projectData, null);

    // import java project data
    JavaProjectData javaProjectData = projectResolverChain.createJavaProjectData();
    projectDataNode.createChild(JavaProjectData.KEY, javaProjectData);

    IdeaProject ideaProject = resolverCtx.getModels().getIdeaProject();
    DomainObjectSet<? extends IdeaModule> gradleModules = ideaProject.getModules();
    if (gradleModules == null || gradleModules.isEmpty()) {
      throw new IllegalStateException("No modules found for the target project: " + ideaProject);
    }
    final Map<String, Pair<DataNode<ModuleData>, IdeaModule>> moduleMap =
        ContainerUtilRt.newHashMap();

    // import modules data
    for (IdeaModule gradleModule : gradleModules) {
      if (gradleModule == null) {
        continue;
      }
      final String moduleName = gradleModule.getName();
      if (moduleName == null) {
        throw new IllegalStateException("Module with undefined name detected: " + gradleModule);
      }

      ModuleData moduleData = projectResolverChain.createModule(gradleModule, projectData);

      Pair<DataNode<ModuleData>, IdeaModule> previouslyParsedModule = moduleMap.get(moduleName);
      if (previouslyParsedModule != null) {
        throw new IllegalStateException(
            String.format(
                "Modules with duplicate name (%s) detected: '%s' and '%s'",
                moduleName, moduleData, previouslyParsedModule));
      }
      DataNode<ModuleData> moduleDataNode =
          projectDataNode.createChild(ProjectKeys.MODULE, moduleData);
      moduleMap.put(
          moduleName, new Pair<DataNode<ModuleData>, IdeaModule>(moduleDataNode, gradleModule));
    }

    // populate modules nodes
    final List<TaskData> allTasks = ContainerUtil.newArrayList();
    for (final Pair<DataNode<ModuleData>, IdeaModule> pair : moduleMap.values()) {
      final DataNode<ModuleData> moduleDataNode = pair.first;
      final IdeaModule ideaModule = pair.second;
      projectResolverChain.populateModuleExtraModels(ideaModule, moduleDataNode);
      projectResolverChain.populateModuleContentRoots(ideaModule, moduleDataNode);
      projectResolverChain.populateModuleCompileOutputSettings(ideaModule, moduleDataNode);
      projectResolverChain.populateModuleDependencies(ideaModule, moduleDataNode, projectDataNode);
      final Collection<TaskData> moduleTasks =
          projectResolverChain.populateModuleTasks(ideaModule, moduleDataNode, projectDataNode);
      allTasks.addAll(moduleTasks);
    }

    // populate root project tasks
    final Collection<TaskData> rootProjectTaskCandidates =
        projectResolverChain.filterRootProjectTasks(allTasks);

    Set<Pair<String /* task name */, String /* task description */>> rootProjectTaskCandidatesMap =
        ContainerUtilRt.newHashSet();
    for (final TaskData taskData : rootProjectTaskCandidates) {
      rootProjectTaskCandidatesMap.add(Pair.create(taskData.getName(), taskData.getDescription()));
    }
    for (final Pair<String, String> p : rootProjectTaskCandidatesMap) {
      projectDataNode.createChild(
          ProjectKeys.TASK,
          new TaskData(
              GradleConstants.SYSTEM_ID,
              p.first,
              projectData.getLinkedExternalProjectPath(),
              p.second));
    }

    // ensure unique library names
    Collection<DataNode<LibraryData>> libraries =
        ExternalSystemApiUtil.getChildren(projectDataNode, ProjectKeys.LIBRARY);
    myLibraryNamesMixer.mixNames(libraries);

    return projectDataNode;
  }
  public void importData(
      @NotNull final Collection<DataNode<LibraryDependencyData>> nodesToImport,
      @NotNull final Module module,
      final boolean synchronous) {
    ExternalSystemApiUtil.executeProjectChangeAction(
        synchronous,
        new Runnable() {
          @Override
          public void run() {
            importMissingProjectLibraries(module, nodesToImport, synchronous);

            // The general idea is to import all external project library dependencies and module
            // libraries which don't present at the
            // ide side yet and remove all project library dependencies and module libraries which
            // present at the ide but not at
            // the given collection.
            // The trick is that we should perform module settings modification inside try/finally
            // block against target root model.
            // That means that we need to prepare all necessary data, obtain a model and modify it
            // as necessary.
            Map<Set<String> /* library paths */, LibraryDependencyData> moduleLibrariesToImport =
                ContainerUtilRt.newHashMap();
            Map<String /* library name */, LibraryDependencyData> projectLibrariesToImport =
                ContainerUtilRt.newHashMap();
            Set<LibraryDependencyData> toImport = ContainerUtilRt.newLinkedHashSet();

            boolean hasUnresolved = false;
            for (DataNode<LibraryDependencyData> dependencyNode : nodesToImport) {
              LibraryDependencyData dependencyData = dependencyNode.getData();
              LibraryData libraryData = dependencyData.getTarget();
              hasUnresolved |= libraryData.isUnresolved();
              switch (dependencyData.getLevel()) {
                case MODULE:
                  if (!libraryData.isUnresolved()) {
                    Set<String> paths = ContainerUtilRt.newHashSet();
                    for (String path : libraryData.getPaths(LibraryPathType.BINARY)) {
                      paths.add(ExternalSystemApiUtil.toCanonicalPath(path));
                    }
                    moduleLibrariesToImport.put(paths, dependencyData);
                    toImport.add(dependencyData);
                  }
                  break;
                case PROJECT:
                  projectLibrariesToImport.put(libraryData.getName(), dependencyData);
                  toImport.add(dependencyData);
              }
            }

            ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
            final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel();
            LibraryTable moduleLibraryTable = moduleRootModel.getModuleLibraryTable();
            LibraryTable libraryTable =
                myPlatformFacade.getProjectLibraryTable(module.getProject());
            try {
              if (!hasUnresolved) { // There is a possible case that a project has been successfully
                                    // imported from external model and after
                // that network/repo goes down. We don't want to drop existing binary mappings then.
                removeObsolete(
                    moduleLibrariesToImport, projectLibrariesToImport, toImport, moduleRootModel);
              }

              // Import missing library dependencies.
              if (!toImport.isEmpty()) {
                importMissing(toImport, moduleRootModel, moduleLibraryTable, libraryTable, module);
              }
            } finally {
              moduleRootModel.commit();
            }
          }
        });
  }
  @NotNull
  private Map<String, GradleModuleResourceConfiguration> generateAffectedGradleModulesConfiguration(
      @NotNull CompileContext context) {
    final Map<String, GradleModuleResourceConfiguration> affectedGradleModuleConfigurations =
        ContainerUtil.newTroveMap();

    //noinspection MismatchedQueryAndUpdateOfCollection
    final Map<String, ExternalProject> lazyExternalProjectMap =
        new FactoryMap<String, ExternalProject>() {
          @Nullable
          @Override
          protected ExternalProject create(String gradleProjectPath) {
            return myExternalProjectDataService.getRootExternalProject(
                GradleConstants.SYSTEM_ID, new File(gradleProjectPath));
          }
        };

    for (Module module : context.getCompileScope().getAffectedModules()) {
      if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module))
        continue;

      if (shouldBeBuiltByExternalSystem(module)) continue;

      final String gradleProjectPath =
          module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY);
      assert gradleProjectPath != null;
      final ExternalProject externalRootProject = lazyExternalProjectMap.get(gradleProjectPath);
      if (externalRootProject == null) {
        context.addMessage(
            CompilerMessageCategory.ERROR,
            String.format(
                "Unable to make the module: %s, related gradle configuration was not found. "
                    + "Please, re-import the Gradle project and try again.",
                module.getName()),
            VfsUtilCore.pathToUrl(gradleProjectPath),
            -1,
            -1);
        continue;
      }

      ExternalProject externalProject =
          myExternalProjectDataService.findExternalProject(externalRootProject, module);
      if (externalProject == null) {
        LOG.warn("Unable to find config for module: " + module.getName());
        continue;
      }

      GradleModuleResourceConfiguration resourceConfig = new GradleModuleResourceConfiguration();
      resourceConfig.id =
          new ModuleVersion(
              externalProject.getGroup(), externalProject.getName(), externalProject.getVersion());
      resourceConfig.directory =
          FileUtil.toSystemIndependentName(externalProject.getProjectDir().getPath());

      final ExternalSourceSet mainSourcesSet = externalProject.getSourceSets().get("main");
      addResources(resourceConfig.resources, mainSourcesSet, ExternalSystemSourceType.RESOURCE);

      final ExternalSourceSet testSourcesSet = externalProject.getSourceSets().get("test");
      addResources(
          resourceConfig.testResources, testSourcesSet, ExternalSystemSourceType.TEST_RESOURCE);

      final CompilerModuleExtension compilerModuleExtension =
          CompilerModuleExtension.getInstance(module);
      if (compilerModuleExtension != null
          && compilerModuleExtension.isCompilerOutputPathInherited()) {
        String outputPath = VfsUtilCore.urlToPath(compilerModuleExtension.getCompilerOutputUrl());
        for (ResourceRootConfiguration resource : resourceConfig.resources) {
          resource.targetPath = outputPath;
        }

        String testOutputPath =
            VfsUtilCore.urlToPath(compilerModuleExtension.getCompilerOutputUrlForTests());
        for (ResourceRootConfiguration resource : resourceConfig.testResources) {
          resource.targetPath = testOutputPath;
        }
      }

      affectedGradleModuleConfigurations.put(module.getName(), resourceConfig);
    }

    return affectedGradleModuleConfigurations;
  }
  public KeymapGroup createGroup(Condition<AnAction> condition, final Project project) {
    KeymapGroup result =
        KeymapGroupFactory.getInstance()
            .createGroup(
                ExternalSystemBundle.message("external.system.keymap.group"),
                ExternalSystemIcons.TaskGroup);
    if (project == null) return result;

    MultiMap<ProjectSystemId, String> projectToActionsMapping = MultiMap.create();
    for (ExternalSystemManager<?, ?, ?, ?, ?> manager : ExternalSystemApiUtil.getAllManagers()) {
      projectToActionsMapping.putValues(manager.getSystemId(), ContainerUtil.<String>emptyList());
    }

    ActionManager actionManager = ActionManager.getInstance();
    if (actionManager != null) {
      for (String eachId : actionManager.getActionIds(getActionPrefix(project, null))) {
        AnAction eachAction = actionManager.getAction(eachId);

        if (!(eachAction instanceof MyExternalSystemAction)) continue;
        if (condition != null && !condition.value(actionManager.getActionOrStub(eachId))) continue;

        MyExternalSystemAction taskAction = (MyExternalSystemAction) eachAction;
        projectToActionsMapping.putValue(taskAction.getSystemId(), eachId);
      }
    }

    Map<ProjectSystemId, KeymapGroup> keymapGroupMap = ContainerUtil.newHashMap();
    for (ProjectSystemId systemId : projectToActionsMapping.keySet()) {
      if (!keymapGroupMap.containsKey(systemId)) {
        final Icon projectIcon = ExternalSystemUiUtil.getUiAware(systemId).getProjectIcon();
        KeymapGroup group =
            KeymapGroupFactory.getInstance().createGroup(systemId.getReadableName(), projectIcon);
        result.addGroup(group);
        keymapGroupMap.put(systemId, group);
      }
    }

    for (Map.Entry<ProjectSystemId, Collection<String>> each : projectToActionsMapping.entrySet()) {
      Collection<String> tasks = each.getValue();
      final ProjectSystemId systemId = each.getKey();
      final KeymapGroup systemGroup = keymapGroupMap.get(systemId);
      for (String actionId : tasks) {
        systemGroup.addActionId(actionId);
      }
      if (systemGroup instanceof Group) {
        Icon icon =
            SystemInfoRt.isMac ? AllIcons.ToolbarDecorator.Mac.Add : AllIcons.ToolbarDecorator.Add;
        ((Group) systemGroup)
            .addHyperlink(
                new Hyperlink(icon, "Choose a task to assign a shortcut") {
                  @Override
                  public void onClick(MouseEvent e) {
                    SelectExternalTaskDialog dialog =
                        new SelectExternalTaskDialog(systemId, project);
                    if (dialog.showAndGet() && dialog.getResult() != null) {
                      TaskData taskData = dialog.getResult().second;
                      String ownerModuleName = dialog.getResult().first;
                      ExternalSystemTaskAction externalSystemAction =
                          (ExternalSystemTaskAction)
                              getOrRegisterAction(project, ownerModuleName, taskData);

                      ApplicationManager.getApplication()
                          .getMessageBus()
                          .syncPublisher(KeymapListener.CHANGE_TOPIC)
                          .processCurrentKeymapChanged();

                      Settings allSettings =
                          Settings.KEY.getData(
                              DataManager.getInstance().getDataContext(e.getComponent()));
                      KeymapPanel keymapPanel =
                          allSettings != null ? allSettings.find(KeymapPanel.class) : null;
                      if (keymapPanel != null) {
                        // clear actions filter
                        keymapPanel.showOption("");
                        keymapPanel.selectAction(externalSystemAction.myId);
                      }
                    }
                  }
                });
      }
    }

    for (ActionsProvider extension : ActionsProvider.EP_NAME.getExtensions()) {
      KeymapGroup group = extension.createGroup(condition, project);
      if (group != null) {
        result.addGroup(group);
      }
    }

    return result;
  }
  private void importData(
      @NotNull final Collection<DataNode<ModuleDependencyData>> toImport,
      @NotNull final Module module,
      @NotNull final PlatformFacade platformFacade,
      final boolean synchronous) {
    ExternalSystemApiUtil.executeProjectChangeAction(
        synchronous,
        new DisposeAwareProjectChange(module) {
          @Override
          public void execute() {
            ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
            Map<
                    Pair<
                        String /* dependency module internal name */, /* dependency module scope */
                        DependencyScope>,
                    ModuleOrderEntry>
                toRemove = ContainerUtilRt.newHashMap();
            for (OrderEntry entry : moduleRootManager.getOrderEntries()) {
              if (entry instanceof ModuleOrderEntry) {
                ModuleOrderEntry e = (ModuleOrderEntry) entry;
                toRemove.put(Pair.create(e.getModuleName(), e.getScope()), e);
              }
            }

            final ModifiableRootModel moduleRootModel =
                platformFacade.getModuleModifiableModel(module);
            try {
              for (DataNode<ModuleDependencyData> dependencyNode : toImport) {
                final ModuleDependencyData dependencyData = dependencyNode.getData();
                toRemove.remove(
                    Pair.create(dependencyData.getInternalName(), dependencyData.getScope()));
                final String moduleName = dependencyData.getInternalName();
                Module ideDependencyModule =
                    platformFacade.findIdeModule(moduleName, module.getProject());

                ModuleOrderEntry orderEntry;
                if (module.equals(ideDependencyModule)) {
                  // skip recursive module dependency check
                  continue;
                } else {
                  if (ideDependencyModule == null) {
                    LOG.warn(
                        String.format(
                            "Can't import module dependency for '%s' module. Reason: target module (%s) is not found at the ide",
                            module.getName(), dependencyData));
                  }
                  orderEntry =
                      platformFacade.findIdeModuleDependency(dependencyData, moduleRootModel);
                  if (orderEntry == null) {
                    orderEntry =
                        ideDependencyModule == null
                            ? moduleRootModel.addInvalidModuleEntry(moduleName)
                            : moduleRootModel.addModuleOrderEntry(ideDependencyModule);
                  }
                }

                orderEntry.setScope(dependencyData.getScope());
                orderEntry.setExported(dependencyData.isExported());
              }
            } finally {
              moduleRootModel.commit();
            }

            if (!toRemove.isEmpty()) {
              removeData(toRemove.values(), module, platformFacade, synchronous);
            }
          }
        });
  }
  @Override
  public void computeInReadAction(@NotNull ProgressIndicator indicator) {
    if (myProject.isDisposed()) return;
    if (ApplicationManager.getApplication().isUnitTestMode()) return;

    final LocalFileSystem localFileSystem = LocalFileSystem.getInstance();
    final List<PsiFile> psiFileList = ContainerUtil.newArrayList();

    final ModuleManager moduleManager = ModuleManager.getInstance(myProject);
    for (Module module : moduleManager.getModules()) {
      if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module))
        continue;

      final String modulePath = ExternalSystemApiUtil.getExternalProjectPath(module);
      if (modulePath == null) continue;

      String buildScript =
          FileUtil.findFileInProvidedPath(modulePath, GradleConstants.DEFAULT_SCRIPT_NAME);
      if (StringUtil.isEmpty(buildScript)) continue;

      VirtualFile virtualFile = localFileSystem.refreshAndFindFileByPath(buildScript);
      if (virtualFile == null) continue;

      final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(virtualFile);
      if (psiFile == null) continue;
      psiFileList.add(psiFile);
    }

    final PsiFile[] psiFiles = ArrayUtil.toObjectArray(psiFileList, PsiFile.class);

    final Set<MavenRemoteRepository> mavenRemoteRepositories =
        new ReadAction<Set<MavenRemoteRepository>>() {
          @Override
          protected void run(@NotNull Result<Set<MavenRemoteRepository>> result) throws Throwable {
            Set<MavenRemoteRepository> myRemoteRepositories = ContainerUtil.newHashSet();
            for (PsiFile psiFile : psiFiles) {
              List<GrClosableBlock> repositoriesBlocks = ContainerUtil.newArrayList();
              repositoriesBlocks.addAll(findClosableBlocks(psiFile, "repositories"));

              for (GrClosableBlock closableBlock :
                  findClosableBlocks(
                      psiFile,
                      "buildscript",
                      "subprojects",
                      "allprojects",
                      "project",
                      "configure")) {
                repositoriesBlocks.addAll(findClosableBlocks(closableBlock, "repositories"));
              }

              for (GrClosableBlock repositoriesBlock : repositoriesBlocks) {
                myRemoteRepositories.addAll(findMavenRemoteRepositories(repositoriesBlock));
              }
            }

            result.setResult(myRemoteRepositories);
          }
        }.execute().getResultObject();

    if (mavenRemoteRepositories == null || mavenRemoteRepositories.isEmpty()) return;

    // register imported maven repository URLs but do not force to download the index
    // the index can be downloaded and/or updated later using Maven Configuration UI (Settings ->
    // Build, Execution, Deployment -> Build tools -> Maven -> Repositories)
    MavenRepositoriesHolder.getInstance(myProject).update(mavenRemoteRepositories);
    MavenProjectIndicesManager.getInstance(myProject)
        .scheduleUpdateIndicesList(
            new Consumer<List<MavenIndex>>() {
              @Override
              public void consume(List<MavenIndex> indexes) {
                if (myProject.isDisposed()) return;

                final List<String> repositoriesWithEmptyIndex =
                    ContainerUtil.mapNotNull(
                        indexes,
                        new Function<MavenIndex, String>() {
                          @Override
                          public String fun(MavenIndex index) {
                            return index.getUpdateTimestamp() == -1
                                    && MavenRepositoriesHolder.getInstance(myProject)
                                        .contains(index.getRepositoryPathOrUrl())
                                ? index.getRepositoryPathOrUrl()
                                : null;
                          }
                        });

                if (!repositoriesWithEmptyIndex.isEmpty()) {
                  final NotificationData notificationData =
                      new NotificationData(
                          GradleBundle.message(
                              "gradle.integrations.maven.notification.not_updated_repository.title"),
                          "\n<br>"
                              + GradleBundle.message(
                                  "gradle.integrations.maven.notification.not_updated_repository.text",
                                  StringUtil.join(repositoriesWithEmptyIndex, "<br>")),
                          NotificationCategory.WARNING,
                          NotificationSource.PROJECT_SYNC);
                  notificationData.setBalloonNotification(true);
                  notificationData.setBalloonGroup(UNINDEXED_MAVEN_REPOSITORIES_NOTIFICATION_GROUP);
                  notificationData.setListener(
                      "#open",
                      new NotificationListener.Adapter() {
                        @Override
                        protected void hyperlinkActivated(
                            @NotNull Notification notification, @NotNull HyperlinkEvent e) {
                          ShowSettingsUtil.getInstance()
                              .showSettingsDialog(myProject, MavenRepositoriesConfigurable.class);
                        }
                      });

                  notificationData.setListener(
                      "#disable",
                      new NotificationListener.Adapter() {
                        @Override
                        protected void hyperlinkActivated(
                            @NotNull Notification notification, @NotNull HyperlinkEvent e) {
                          final int result =
                              Messages.showYesNoDialog(
                                  myProject,
                                  "Notification will be disabled for all projects.\n\n"
                                      + "Settings | Appearance & Behavior | Notifications | "
                                      + UNINDEXED_MAVEN_REPOSITORIES_NOTIFICATION_GROUP
                                      + "\ncan be used to configure the notification.",
                                  "Unindexed Maven Repositories Gradle Detection",
                                  "Disable Notification",
                                  CommonBundle.getCancelButtonText(),
                                  Messages.getWarningIcon());
                          if (result == Messages.YES) {
                            NotificationsConfigurationImpl.getInstanceImpl()
                                .changeSettings(
                                    UNINDEXED_MAVEN_REPOSITORIES_NOTIFICATION_GROUP,
                                    NotificationDisplayType.NONE,
                                    false,
                                    false);

                            notification.hideBalloon();
                          }
                        }
                      });

                  ExternalSystemNotificationManager.getInstance(myProject)
                      .showNotification(GradleConstants.SYSTEM_ID, notificationData);
                }
              }
            });
  }
  public ExternalSystemTasksPanel(
      @NotNull Project project,
      @NotNull ProjectSystemId externalSystemId,
      @NotNull NotificationGroup notificationGroup) {
    super(true);
    myExternalSystemId = externalSystemId;
    myNotificationGroup = notificationGroup;
    myProject = project;

    ExternalSystemManager<?, ?, ?, ?, ?> manager =
        ExternalSystemApiUtil.getManager(externalSystemId);
    assert manager != null;
    AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project);

    ExternalSystemRecentTaskListModel recentTasksModel =
        new ExternalSystemRecentTaskListModel(externalSystemId, project);
    recentTasksModel.setTasks(settings.getRecentTasks());
    myRecentTasksList =
        new ExternalSystemRecentTasksList(recentTasksModel, externalSystemId, project) {
          @Override
          protected void processMouseEvent(MouseEvent e) {
            if (e.getClickCount() > 0) {
              mySelectedTaskProvider = myRecentTasksList;
              myAllTasksTree.getSelectionModel().clearSelection();
            }
            super.processMouseEvent(e);
          }
        };

    myAllTasksModel = new ExternalSystemTasksTreeModel(externalSystemId);
    myAllTasksTree =
        new ExternalSystemTasksTree(
            myAllTasksModel, settings.getExpandStates(), project, externalSystemId) {
          @Override
          protected void processMouseEvent(MouseEvent e) {
            if (e.getClickCount() > 0) {
              mySelectedTaskProvider = myAllTasksTree;
              myRecentTasksList.getSelectionModel().clearSelection();
            }
            super.processMouseEvent(e);
          }
        };
    final String actionIdToUseForDoubleClick =
        DefaultRunExecutor.getRunExecutorInstance().getContextActionId();
    myAllTasksTree.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            if (e.getClickCount() >= 2 && !e.isPopupTrigger()) {
              ExternalSystemUiUtil.executeAction(actionIdToUseForDoubleClick, e);
            }
          }
        });
    ExternalSystemUiUtil.apply(settings, myAllTasksModel);
    CustomizationUtil.installPopupHandler(
        myAllTasksTree, TREE_ACTIONS_GROUP_ID, TREE_CONTEXT_MENU_PLACE);

    ActionManager actionManager = ActionManager.getInstance();
    ActionGroup group = (ActionGroup) actionManager.getAction(TOOL_WINDOW_TOOLBAR_ACTIONS_GROUP_ID);
    ActionToolbar toolbar = actionManager.createActionToolbar(TOOL_WINDOW_PLACE, group, true);
    toolbar.setTargetComponent(this);
    setToolbar(toolbar.getComponent());

    JPanel content = new JPanel(new GridBagLayout());
    content.setOpaque(true);
    content.setBackground(UIUtil.getListBackground());
    JComponent recentTasksWithTitle =
        wrap(myRecentTasksList, ExternalSystemBundle.message("tasks.recent.title"));
    content.add(recentTasksWithTitle, ExternalSystemUiUtil.getFillLineConstraints(0));
    JBScrollPane scrollPane = new JBScrollPane(myAllTasksTree);
    scrollPane.setBorder(null);
    JComponent allTasksWithTitle =
        wrap(scrollPane, ExternalSystemBundle.message("tasks.all.title"));
    content.add(
        allTasksWithTitle, ExternalSystemUiUtil.getFillLineConstraints(0).weighty(1).fillCell());
    setContent(content);
  }