IDEA-256658 IDEA-256801 Reader Mode: apply breadcrumbs and doc rendering props change...
[idea/community.git] / java / idea-ui / src / com / intellij / ide / actions / ImportModuleAction.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.ide.actions;
3
4 import com.intellij.ide.JavaUiBundle;
5 import com.intellij.ide.impl.NewProjectUtil;
6 import com.intellij.ide.impl.ProjectUtil;
7 import com.intellij.ide.util.PropertiesComponent;
8 import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard;
9 import com.intellij.ide.util.newProjectWizard.AddModuleWizard;
10 import com.intellij.ide.util.projectWizard.ProjectBuilder;
11 import com.intellij.openapi.actionSystem.AnAction;
12 import com.intellij.openapi.actionSystem.AnActionEvent;
13 import com.intellij.openapi.actionSystem.Presentation;
14 import com.intellij.openapi.diagnostic.Logger;
15 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
16 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
17 import com.intellij.openapi.fileChooser.FileChooserDialog;
18 import com.intellij.openapi.fileChooser.FileChooserFactory;
19 import com.intellij.openapi.module.Module;
20 import com.intellij.openapi.module.ModuleManager;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.project.ProjectManager;
23 import com.intellij.openapi.roots.ui.configuration.actions.NewModuleAction;
24 import com.intellij.openapi.ui.Messages;
25 import com.intellij.openapi.util.NlsContexts;
26 import com.intellij.openapi.util.text.HtmlBuilder;
27 import com.intellij.openapi.vfs.LocalFileSystem;
28 import com.intellij.openapi.vfs.VirtualFile;
29 import com.intellij.projectImport.DeprecatedProjectBuilderForImport;
30 import com.intellij.projectImport.ProjectImportProvider;
31 import com.intellij.util.containers.ContainerUtil;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
34
35 import java.awt.*;
36 import java.nio.file.Paths;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.List;
40
41 /**
42  * @author Dmitry Avdeev
43  */
44 public class ImportModuleAction extends AnAction implements NewProjectOrModuleAction {
45
46   private static final String LAST_IMPORTED_LOCATION = "last.imported.location";
47   private static final Logger LOG = Logger.getInstance(ImportModuleAction.class);
48
49   @Override
50   public void actionPerformed(@NotNull AnActionEvent e) {
51     doImport(getEventProject(e));
52   }
53
54   @Override
55   public void update(@NotNull AnActionEvent e) {
56     Presentation presentation = e.getPresentation();
57     presentation.setEnabled(getEventProject(e) != null);
58     NewProjectAction.updateActionText(this, e);
59   }
60
61   @NotNull
62   @Override
63   public String getActionText(boolean isInNewSubmenu, boolean isInJavaIde) {
64     return JavaUiBundle.message("import.module.action.text", isInNewSubmenu ? 1 : 0, isInJavaIde ? 1 : 0);
65   }
66
67   @Override
68   public boolean isDumbAware() {
69     return true;
70   }
71
72   public static List<Module> doImport(@Nullable Project project) {
73     AddModuleWizard wizard = selectFileAndCreateWizard(project, null);
74
75     if (wizard == null || wizard.getStepCount() > 0 && !wizard.showAndGet()) {
76       return Collections.emptyList();
77     }
78     return createFromWizard(project, wizard);
79   }
80
81   public static List<Module> createFromWizard(@Nullable Project project, AbstractProjectWizard wizard) {
82     try {
83       return doCreateFromWizard(project, wizard);
84     }
85     finally {
86       wizard.disposeIfNeeded();
87     }
88   }
89
90   private static List<Module> doCreateFromWizard(@Nullable Project project, AbstractProjectWizard wizard) {
91     final ProjectBuilder projectBuilder = wizard.getProjectBuilder();
92     if (project == null) {
93       Project newProject;
94       if (projectBuilder instanceof DeprecatedProjectBuilderForImport) {
95         // The path to remove import action
96         newProject = openProject((DeprecatedProjectBuilderForImport)projectBuilder, wizard.getNewProjectFilePath());
97       }
98       else {
99         newProject = NewProjectUtil.createFromWizard(wizard);
100       }
101       return newProject == null ? Collections.emptyList() : Arrays.asList(ModuleManager.getInstance(newProject).getModules());
102     }
103
104     try {
105       if (wizard.getStepCount() > 0) {
106         Module module = new NewModuleAction().createModuleFromWizard(project, null, wizard);
107         return Collections.singletonList(module);
108       }
109       else {
110         if (!projectBuilder.validate(project, project)) {
111           return Collections.emptyList();
112         }
113         return projectBuilder.commit(project);
114       }
115     }
116     finally {
117       if (projectBuilder != null) {
118         projectBuilder.cleanup();
119       }
120     }
121   }
122
123   @Nullable
124   private static Project openProject(@NotNull DeprecatedProjectBuilderForImport projectBuilder, @NotNull String projectPath) {
125     VirtualFile file = ProjectUtil.getFileAndRefresh(Paths.get(projectPath));
126     if (file == null) {
127       LOG.warn(String.format("Cannot find project file in vfs `%s`", projectPath));
128       return null;
129     }
130     return projectBuilder.getProjectOpenProcessor().doOpenProject(file, null, false);
131   }
132
133   @Nullable
134   public static AddModuleWizard selectFileAndCreateWizard(@Nullable Project project, @Nullable Component dialogParent) {
135     FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleLocalFileDescriptor();
136     descriptor.setHideIgnored(false);
137     descriptor.setTitle(JavaUiBundle.message("chooser.title.select.file.or.directory.to.import"));
138     List<ProjectImportProvider> providers = getProviders(project);
139     String description = getFileChooserDescription(providers);
140     descriptor.setDescription(description);
141     return selectFileAndCreateWizard(project, dialogParent, descriptor, providers.toArray(new ProjectImportProvider[0]));
142   }
143
144   @Nullable
145   public static AddModuleWizard selectFileAndCreateWizard(@Nullable Project project,
146                                                           @Nullable Component dialogParent,
147                                                           @NotNull FileChooserDescriptor descriptor,
148                                                           ProjectImportProvider[] providers) {
149     FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, project, dialogParent);
150     VirtualFile toSelect = null;
151     String lastLocation = PropertiesComponent.getInstance().getValue(LAST_IMPORTED_LOCATION);
152     if (lastLocation != null) {
153       toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(lastLocation);
154     }
155     VirtualFile[] files = chooser.choose(project, toSelect);
156     if (files.length == 0) {
157       return null;
158     }
159
160     final VirtualFile file = files[0];
161     if (project == null) { // wizard will create a new project
162       for (Project p : ProjectManager.getInstance().getOpenProjects()) {
163         if (ProjectUtil.isSameProject(file.toNioPath(), p)) {
164           ProjectUtil.focusProjectWindow(p, false);
165           return null;
166         }
167       }
168     }
169     PropertiesComponent.getInstance().setValue(LAST_IMPORTED_LOCATION, file.getPath());
170     return createImportWizard(project, dialogParent, file, providers);
171   }
172
173   private static @NlsContexts.Label String getFileChooserDescription(List<ProjectImportProvider> providers) {
174     HtmlBuilder builder = new HtmlBuilder().append(JavaUiBundle.message("select")).append(" ");
175     boolean first = true;
176     if (providers.size() > 0) {
177       for (ProjectImportProvider provider : providers) {
178         String sample = provider.getFileSample();
179         if (sample != null) {
180           if (!first) {
181             builder.append(", ").br();
182           }
183           else {
184             first = false;
185           }
186           builder.appendRaw(sample);
187         }
188       }
189     }
190     builder.append(".");
191     return builder.wrapWith("html").toString();
192   }
193
194   @NotNull
195   public static List<ProjectImportProvider> getProviders(@Nullable final Project project) {
196     ProjectImportProvider[] providers = ProjectImportProvider.PROJECT_IMPORT_PROVIDER.getExtensions();
197     return ContainerUtil.filter(providers, provider -> project == null ? provider.canCreateNewProject() : provider.canImportModule());
198   }
199
200   @Nullable
201   public static AddModuleWizard createImportWizard(@Nullable final Project project,
202                                                    @Nullable Component dialogParent,
203                                                    @NotNull final VirtualFile file,
204                                                    ProjectImportProvider... providers) {
205     List<ProjectImportProvider> available = ContainerUtil.filter(providers, provider -> provider.canImport(file, project));
206     if (available.isEmpty()) {
207       Messages.showInfoMessage(project, JavaUiBundle.message("message.cannot.import.anything.from.0", file.getPath()),
208                                JavaUiBundle.message("dialog.title.cannot.import"));
209       return null;
210     }
211
212     String path;
213     if (available.size() == 1) {
214       path = available.get(0).getPathToBeImported(file);
215     }
216     else {
217       path = ProjectImportProvider.getDefaultPath(file);
218     }
219
220     ProjectImportProvider[] availableProviders = available.toArray(new ProjectImportProvider[0]);
221
222     return dialogParent == null
223            ? new AddModuleWizard(project, path, availableProviders)
224            : new AddModuleWizard(project, dialogParent, path, availableProviders);
225   }
226 }