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