8489f0042542a62cf8588f219c1041926d586b3a
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / projectRoot / LibrariesContainerFactory.java
1 /*
2  * Copyright 2000-2012 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.roots.ui.configuration.projectRoot;
17
18 import com.intellij.ide.util.projectWizard.WizardContext;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.module.Module;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.roots.*;
23 import com.intellij.openapi.roots.impl.OrderEntryUtil;
24 import com.intellij.openapi.roots.impl.libraries.LibraryEx;
25 import com.intellij.openapi.roots.impl.libraries.LibraryTableBase;
26 import com.intellij.openapi.roots.libraries.Library;
27 import com.intellij.openapi.roots.libraries.LibraryTable;
28 import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
29 import com.intellij.openapi.roots.libraries.LibraryType;
30 import com.intellij.openapi.roots.libraries.ui.OrderRoot;
31 import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider;
32 import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator;
33 import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
34 import com.intellij.openapi.roots.ui.configuration.libraryEditor.ExistingLibraryEditor;
35 import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor;
36 import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor;
37 import com.intellij.openapi.util.Condition;
38 import com.intellij.openapi.util.text.StringUtil;
39 import com.intellij.openapi.vfs.VirtualFile;
40 import com.intellij.util.ArrayUtil;
41 import com.intellij.util.Function;
42 import com.intellij.util.text.UniqueNameGenerator;
43 import org.jetbrains.annotations.NonNls;
44 import org.jetbrains.annotations.NotNull;
45 import org.jetbrains.annotations.Nullable;
46
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Collection;
50 import java.util.List;
51
52 /**
53  * @author nik
54  */
55 public class LibrariesContainerFactory {
56   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory");
57   private static final Library[] EMPTY_LIBRARIES_ARRAY = new Library[0];
58
59   private LibrariesContainerFactory() {
60   }
61
62   @NotNull
63   public static LibrariesContainer createContainer(@Nullable Project project) {
64     return new LibrariesContainerImpl(project, null, null);
65   }
66
67   @NotNull
68   public static LibrariesContainer createContainer(@NotNull Module module) {
69     return new LibrariesContainerImpl(module.getProject(), module, null);
70   }
71
72   @NotNull
73   public static LibrariesContainer createContainer(@NotNull ModifiableRootModel rootModel) {
74     Module module = rootModel.getModule();
75     return new LibrariesContainerImpl(module.getProject(), module, rootModel);
76   }
77
78   public static LibrariesContainer createContainer(StructureConfigurableContext context) {
79     return new StructureConfigurableLibrariesContainer(context);
80   }
81
82   public static Library createLibrary(@Nullable LibrariesContainer container1, @NotNull LibrariesContainer container2,
83                                @NotNull @NonNls final NewLibraryEditor editor, @NotNull final LibrariesContainer.LibraryLevel level) {
84     if (container1 != null && container1.canCreateLibrary(level)) {
85       return container1.createLibrary(editor, level);
86     }
87     else {
88       return container2.createLibrary(editor, level);
89     }
90   }
91
92   @NotNull
93   private static Library createLibraryInTable(final @NotNull NewLibraryEditor editor, final LibraryTable table) {
94     LibraryTableBase.ModifiableModelEx modifiableModel = (LibraryTableBase.ModifiableModelEx) table.getModifiableModel();
95     final String name = StringUtil.isEmpty(editor.getName()) ? null : getUniqueLibraryName(editor.getName(), modifiableModel);
96     final LibraryType<?> type = editor.getType();
97     Library library = modifiableModel.createLibrary(name, type == null ? null : type.getKind());
98     final LibraryEx.ModifiableModelEx model = (LibraryEx.ModifiableModelEx)library.getModifiableModel();
99     editor.applyTo(model);
100     model.commit();
101     modifiableModel.commit();
102     return library;
103   }
104
105   private static String getUniqueLibraryName(final String baseName, final LibraryTable.ModifiableModel model) {
106     return UniqueNameGenerator.generateUniqueName(baseName, "", "", " (", ")", new Condition<String>() {
107       @Override
108       public boolean value(String s) {
109         return model.getLibraryByName(s) == null;
110       }
111     });
112   }
113
114   @NotNull
115   public static LibrariesContainer createContainer(@NotNull WizardContext context, @NotNull ModulesProvider modulesProvider) {
116     final LibrariesContainer container;
117     if (modulesProvider instanceof ModulesConfigurator) {
118       ModulesConfigurator configurator = (ModulesConfigurator)modulesProvider;
119       container = createContainer(configurator.getContext());
120     }
121     else {
122       container = createContainer(context.getProject());
123     }
124     return container;
125   }
126
127
128   private abstract static class LibrariesContainerBase implements LibrariesContainer {
129     private UniqueNameGenerator myNameGenerator;
130
131     @Override
132     public Library createLibrary(@NotNull @NonNls String name,
133                                  @NotNull LibraryLevel level,
134                                  @NotNull VirtualFile[] classRoots,
135                                  @NotNull VirtualFile[] sourceRoots) {
136       NewLibraryEditor editor = new NewLibraryEditor();
137       editor.setName(name);
138       for (VirtualFile classRoot : classRoots) {
139         editor.addRoot(classRoot, OrderRootType.CLASSES);
140       }
141       for (VirtualFile sourceRoot : sourceRoots) {
142         editor.addRoot(sourceRoot, OrderRootType.SOURCES);
143       }
144       return createLibrary(editor, level);
145     }
146
147     @Override
148     public Library createLibrary(@NotNull @NonNls String name,
149                                  @NotNull LibraryLevel level,
150                                  @NotNull Collection<? extends OrderRoot> roots) {
151       final NewLibraryEditor editor = new NewLibraryEditor();
152       editor.setName(name);
153       editor.addRoots(roots);
154       return createLibrary(editor, level);
155     }
156
157     @Override
158     @NotNull
159     public Library[] getAllLibraries() {
160       Library[] libraries = getLibraries(LibraryLevel.GLOBAL);
161       Library[] projectLibraries = getLibraries(LibraryLevel.PROJECT);
162       if (projectLibraries.length > 0) {
163         libraries = ArrayUtil.mergeArrays(libraries, projectLibraries);
164       }
165       Library[] moduleLibraries = getLibraries(LibraryLevel.MODULE);
166       if (moduleLibraries.length > 0) {
167         libraries = ArrayUtil.mergeArrays(libraries, moduleLibraries);
168       }
169       return libraries;
170     }
171
172     @NotNull
173     @Override
174     public List<LibraryLevel> getAvailableLevels() {
175       final List<LibraryLevel> levels = new ArrayList<LibraryLevel>();
176       for (LibraryLevel level : LibraryLevel.values()) {
177         if (canCreateLibrary(level)) {
178           levels.add(level);
179         }
180       }
181       return levels;
182     }
183
184     @NotNull
185     @Override
186     public String suggestUniqueLibraryName(@NotNull String baseName) {
187       if (myNameGenerator == null) {
188         myNameGenerator = new UniqueNameGenerator(Arrays.asList(getAllLibraries()), new Function<Library, String>() {
189           @Override
190           public String fun(Library o) {
191             return o.getName();
192           }
193         });
194       }
195       return myNameGenerator.generateUniqueName(baseName, "", "", " (", ")");
196     }
197   }
198
199
200   private static class LibrariesContainerImpl extends LibrariesContainerBase {
201     private @Nullable final Project myProject;
202     @Nullable private final Module myModule;
203     @Nullable private final ModifiableRootModel myRootModel;
204
205     private LibrariesContainerImpl(final @Nullable Project project, final @Nullable Module module, final @Nullable ModifiableRootModel rootModel) {
206       myProject = project;
207       myModule = module;
208       myRootModel = rootModel;
209     }
210
211     @Override
212     @Nullable
213     public Project getProject() {
214       return myProject;
215     }
216
217     @Override
218     @NotNull
219     public Library[] getLibraries(@NotNull final LibraryLevel libraryLevel) {
220       if (libraryLevel == LibraryLevel.MODULE && myModule != null) {
221         return getModuleLibraries();
222       }
223
224       LibraryTablesRegistrar registrar = LibraryTablesRegistrar.getInstance();
225       if (libraryLevel == LibraryLevel.GLOBAL) {
226         return registrar.getLibraryTable().getLibraries();
227       }
228
229       if (libraryLevel == LibraryLevel.PROJECT && myProject != null) {
230         return registrar.getLibraryTable(myProject).getLibraries();
231       }
232
233       return EMPTY_LIBRARIES_ARRAY;
234     }
235
236     private Library[] getModuleLibraries() {
237       if (myRootModel != null) {
238         return myRootModel.getModuleLibraryTable().getLibraries();
239       }
240       List<Library> libraries = OrderEntryUtil.getModuleLibraries(ModuleRootManager.getInstance(myModule));
241       return libraries.toArray(new Library[libraries.size()]);
242     }
243
244     @Override
245     @NotNull
246     public VirtualFile[] getLibraryFiles(@NotNull final Library library, @NotNull final OrderRootType rootType) {
247       return library.getFiles(rootType);
248     }
249
250     @Override
251     public boolean canCreateLibrary(@NotNull final LibraryLevel level) {
252       if (level == LibraryLevel.MODULE) {
253         return myRootModel != null;
254       }
255       return level == LibraryLevel.GLOBAL || myProject != null;
256     }
257
258     @Override
259     public Library createLibrary(@NotNull NewLibraryEditor libraryEditor,
260                                  @NotNull LibraryLevel level) {
261       if (level == LibraryLevel.MODULE && myRootModel != null) {
262         return createLibraryInTable(libraryEditor, myRootModel.getModuleLibraryTable());
263       }
264
265       LibraryTablesRegistrar registrar = LibraryTablesRegistrar.getInstance();
266       LibraryTable table;
267       if (level == LibraryLevel.GLOBAL) {
268         table = registrar.getLibraryTable();
269       }
270       else if (level == LibraryLevel.PROJECT && myProject != null) {
271         table = registrar.getLibraryTable(myProject);
272       }
273       else {
274         return null;
275       }
276       return createLibraryInTable(libraryEditor, table);
277     }
278
279     @Override
280     public ExistingLibraryEditor getLibraryEditor(@NotNull Library library) {
281       return null;
282     }
283   }
284
285   private static class StructureConfigurableLibrariesContainer extends LibrariesContainerBase {
286     private final StructureConfigurableContext myContext;
287
288     public StructureConfigurableLibrariesContainer(final StructureConfigurableContext context) {
289       myContext = context;
290     }
291
292     @Override
293     public Library createLibrary(@NotNull NewLibraryEditor libraryEditor,
294                                  @NotNull LibraryLevel level) {
295       LibraryTableModifiableModelProvider provider = getProvider(level);
296       if (provider == null) {
297         LOG.error("cannot create module library in this context");
298       }
299
300       LibraryTableBase.ModifiableModelEx model = (LibraryTableBase.ModifiableModelEx)provider.getModifiableModel();
301       final LibraryType<?> type = libraryEditor.getType();
302       Library library = model.createLibrary(getUniqueLibraryName(libraryEditor.getName(), model), type == null ? null : type.getKind());
303       ExistingLibraryEditor createdLibraryEditor = ((LibrariesModifiableModel)model).getLibraryEditor(library);
304       createdLibraryEditor.setProperties(libraryEditor.getProperties());
305       libraryEditor.applyTo(createdLibraryEditor);
306       return library;
307     }
308
309     @Override
310     public ExistingLibraryEditor getLibraryEditor(@NotNull Library library) {
311       final LibraryTable table = library.getTable();
312       if (table == null) return null;
313
314       final LibraryTable.ModifiableModel model = myContext.getModifiableLibraryTable(table);
315       if (model instanceof LibrariesModifiableModel) {
316         return ((LibrariesModifiableModel)model).getLibraryEditor(library);
317       }
318       return null;
319     }
320
321     @Override
322     @Nullable
323     public Project getProject() {
324       return myContext.getProject();
325     }
326
327     @Override
328     @NotNull
329     public Library[] getLibraries(@NotNull final LibraryLevel libraryLevel) {
330       LibraryTableModifiableModelProvider provider = getProvider(libraryLevel);
331       return provider != null ? provider.getModifiableModel().getLibraries() : EMPTY_LIBRARIES_ARRAY;
332     }
333
334     @Nullable
335     private LibraryTableModifiableModelProvider getProvider(LibraryLevel libraryLevel) {
336       if (libraryLevel == LibraryLevel.PROJECT) {
337         return myContext.getProjectLibrariesProvider();
338       }
339       else if (libraryLevel == LibraryLevel.GLOBAL) {
340         return myContext.getGlobalLibrariesProvider();
341       }
342       else {
343         return null;
344       }
345     }
346
347     @Override
348     public boolean canCreateLibrary(@NotNull final LibraryLevel level) {
349       return level == LibraryLevel.GLOBAL || level == LibraryLevel.PROJECT;
350     }
351
352     @Override
353     @NotNull
354     public VirtualFile[] getLibraryFiles(@NotNull final Library library, @NotNull final OrderRootType rootType) {
355       LibrariesModifiableModel projectLibrariesModel = myContext.getProjectLibrariesProvider().getModifiableModel();
356       if (projectLibrariesModel.hasLibraryEditor(library)) {
357         LibraryEditor libraryEditor = projectLibrariesModel.getLibraryEditor(library);
358         return libraryEditor.getFiles(rootType);
359       }
360       LibrariesModifiableModel globalLibraries = myContext.getGlobalLibrariesProvider().getModifiableModel();
361       if (globalLibraries.hasLibraryEditor(library)) {
362         LibraryEditor libraryEditor = globalLibraries.getLibraryEditor(library);
363         return libraryEditor.getFiles(rootType);
364       }
365       return library.getFiles(rootType);
366     }
367   }
368 }