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);
      }
    }
  }
 @NotNull
 private ExternalProjectSettings getCurrentExternalProjectSettings() {
   ExternalProjectSettings result = myControl.getProjectSettings().clone();
   File externalProjectConfigFile =
       getExternalProjectConfigToUse(new File(result.getExternalProjectPath()));
   final String linkedProjectPath = FileUtil.toCanonicalPath(externalProjectConfigFile.getPath());
   assert linkedProjectPath != null;
   result.setExternalProjectPath(linkedProjectPath);
   return result;
 }
  /**
   * Tries to obtain external project info implied by the given settings and link that external
   * project to the given ide project.
   *
   * @param externalSystemId target external system
   * @param projectSettings settings of the external project to link
   * @param project target ide project to link external project to
   * @param executionResultCallback it might take a while to resolve external project info, that's
   *     why it's possible to provide a callback to be notified on processing result. It receives
   *     <code>true</code> if an external project has been successfully linked to the given ide
   *     project; <code>false</code> otherwise (note that corresponding notification with error
   *     details is expected to be shown to the end-user then)
   * @param isPreviewMode flag which identifies if missing external project binaries should be
   *     downloaded
   * @param progressExecutionMode identifies how progress bar will be represented for the current
   *     processing
   */
  @SuppressWarnings("UnusedDeclaration")
  public static void linkExternalProject(
      @NotNull final ProjectSystemId externalSystemId,
      @NotNull final ExternalProjectSettings projectSettings,
      @NotNull final Project project,
      @Nullable final Consumer<Boolean> executionResultCallback,
      boolean isPreviewMode,
      @NotNull final ProgressExecutionMode progressExecutionMode) {
    ExternalProjectRefreshCallback callback =
        new ExternalProjectRefreshCallback() {
          @SuppressWarnings("unchecked")
          @Override
          public void onSuccess(@Nullable final DataNode<ProjectData> externalProject) {
            if (externalProject == null) {
              if (executionResultCallback != null) {
                executionResultCallback.consume(false);
              }
              return;
            }
            AbstractExternalSystemSettings systemSettings =
                ExternalSystemApiUtil.getSettings(project, externalSystemId);
            Set<ExternalProjectSettings> projects =
                ContainerUtilRt.newHashSet(systemSettings.getLinkedProjectsSettings());
            projects.add(projectSettings);
            systemSettings.setLinkedProjectsSettings(projects);
            ensureToolWindowInitialized(project, externalSystemId);
            ExternalSystemApiUtil.executeProjectChangeAction(
                new DisposeAwareProjectChange(project) {
                  @Override
                  public void execute() {
                    ProjectRootManagerEx.getInstanceEx(project)
                        .mergeRootsChangesDuring(
                            new Runnable() {
                              @Override
                              public void run() {
                                ProjectDataManager dataManager =
                                    ServiceManager.getService(ProjectDataManager.class);
                                dataManager.importData(
                                    externalProject.getKey(),
                                    Collections.singleton(externalProject),
                                    project,
                                    true);
                              }
                            });
                  }
                });
            if (executionResultCallback != null) {
              executionResultCallback.consume(true);
            }
          }

          @Override
          public void onFailure(@NotNull String errorMessage, @Nullable String errorDetails) {
            if (executionResultCallback != null) {
              executionResultCallback.consume(false);
            }
          }
        };
    refreshProject(
        project,
        externalSystemId,
        projectSettings.getExternalProjectPath(),
        callback,
        isPreviewMode,
        progressExecutionMode);
  }
  /**
   * Asks to refresh all external projects of the target external system linked to the given ide
   * project based on provided spec
   *
   * @param specBuilder import specification builder
   */
  public static void refreshProjects(@NotNull final ImportSpecBuilder specBuilder) {
    ImportSpec spec = specBuilder.build();

    ExternalSystemManager<?, ?, ?, ?, ?> manager =
        ExternalSystemApiUtil.getManager(spec.getExternalSystemId());
    if (manager == null) {
      return;
    }
    AbstractExternalSystemSettings<?, ?, ?> settings =
        manager.getSettingsProvider().fun(spec.getProject());
    final Collection<? extends ExternalProjectSettings> projectsSettings =
        settings.getLinkedProjectsSettings();
    if (projectsSettings.isEmpty()) {
      return;
    }

    final ProjectDataManager projectDataManager =
        ServiceManager.getService(ProjectDataManager.class);
    final int[] counter = new int[1];

    ExternalProjectRefreshCallback callback =
        new MyMultiExternalProjectRefreshCallback(
            spec.getProject(), projectDataManager, counter, spec.getExternalSystemId());

    Map<String, Long> modificationStamps =
        manager
            .getLocalSettingsProvider()
            .fun(spec.getProject())
            .getExternalConfigModificationStamps();
    Set<String> toRefresh = ContainerUtilRt.newHashSet();
    for (ExternalProjectSettings setting : projectsSettings) {

      // don't refresh project when auto-import is disabled if such behavior needed (e.g. on project
      // opening when auto-import is disabled)
      if (!setting.isUseAutoImport() && spec.isWhenAutoImportEnabled()) continue;

      if (spec.isForceWhenUptodate()) {
        toRefresh.add(setting.getExternalProjectPath());
      } else {
        Long oldModificationStamp = modificationStamps.get(setting.getExternalProjectPath());
        long currentModificationStamp = getTimeStamp(setting, spec.getExternalSystemId());
        if (oldModificationStamp == null || oldModificationStamp < currentModificationStamp) {
          toRefresh.add(setting.getExternalProjectPath());
        }
      }
    }

    if (!toRefresh.isEmpty()) {
      ExternalSystemNotificationManager.getInstance(spec.getProject())
          .clearNotifications(null, NotificationSource.PROJECT_SYNC, spec.getExternalSystemId());

      counter[0] = toRefresh.size();
      for (String path : toRefresh) {
        refreshProject(
            spec.getProject(),
            spec.getExternalSystemId(),
            path,
            callback,
            false,
            spec.getProgressExecutionMode());
      }
    }
  }