2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.intellij
.ide
.util
.newProjectWizard
;
19 import com
.intellij
.facet
.impl
.ui
.libraries
.LibraryCompositionOptionsPanel
;
20 import com
.intellij
.facet
.impl
.ui
.libraries
.LibraryCompositionSettings
;
21 import com
.intellij
.facet
.impl
.ui
.libraries
.LibraryDownloadingMirrorsMap
;
22 import com
.intellij
.facet
.ui
.FacetBasedFrameworkSupportProvider
;
23 import com
.intellij
.facet
.ui
.libraries
.LibraryDownloadInfo
;
24 import com
.intellij
.facet
.ui
.libraries
.LibraryInfo
;
25 import com
.intellij
.facet
.ui
.libraries
.RemoteRepositoryInfo
;
26 import com
.intellij
.ide
.util
.frameworkSupport
.FrameworkSupportConfigurable
;
27 import com
.intellij
.ide
.util
.frameworkSupport
.FrameworkSupportConfigurableListener
;
28 import com
.intellij
.ide
.util
.frameworkSupport
.FrameworkSupportProvider
;
29 import com
.intellij
.ide
.util
.newProjectWizard
.impl
.FrameworkSupportModelImpl
;
30 import com
.intellij
.ide
.util
.projectWizard
.ModuleBuilder
;
31 import com
.intellij
.openapi
.diagnostic
.Logger
;
32 import com
.intellij
.openapi
.module
.Module
;
33 import com
.intellij
.openapi
.roots
.ModifiableRootModel
;
34 import com
.intellij
.openapi
.roots
.libraries
.Library
;
35 import com
.intellij
.openapi
.roots
.ui
.configuration
.projectRoot
.LibrariesContainer
;
36 import com
.intellij
.openapi
.ui
.Splitter
;
37 import com
.intellij
.openapi
.ui
.VerticalFlowLayout
;
38 import com
.intellij
.openapi
.util
.Comparing
;
39 import com
.intellij
.openapi
.util
.Computable
;
40 import com
.intellij
.openapi
.util
.MultiValuesMap
;
41 import com
.intellij
.openapi
.util
.Pair
;
42 import com
.intellij
.ui
.CheckedTreeNode
;
43 import com
.intellij
.ui
.IdeBorderFactory
;
44 import com
.intellij
.ui
.ScrollPaneFactory
;
45 import com
.intellij
.ui
.SeparatorFactory
;
46 import com
.intellij
.util
.graph
.CachingSemiGraph
;
47 import com
.intellij
.util
.graph
.DFSTBuilder
;
48 import com
.intellij
.util
.graph
.GraphGenerator
;
49 import org
.jetbrains
.annotations
.NonNls
;
50 import org
.jetbrains
.annotations
.NotNull
;
51 import org
.jetbrains
.annotations
.Nullable
;
54 import javax
.swing
.event
.TreeSelectionEvent
;
55 import javax
.swing
.event
.TreeSelectionListener
;
58 import java
.util
.List
;
63 public class AddSupportForFrameworksPanel
{
64 private static final Logger LOG
= Logger
.getInstance("#com.intellij.ide.util.newProjectWizard.AddSupportForFrameworksStep");
65 @NonNls private static final String UNCHECKED_CARD
= "unchecked";
66 @NonNls private static final String EMPTY_CARD
= "empty";
67 private JPanel myMainPanel
;
68 private JPanel myFrameworksPanel
;
69 private List
<List
<FrameworkSupportNode
>> myGroups
;
70 private final LibrariesContainer myLibrariesContainer
;
71 private final Computable
<String
> myBaseDirForLibrariesGetter
;
72 private final List
<FrameworkSupportProvider
> myProviders
;
73 private final LibraryDownloadingMirrorsMap myMirrorsMap
;
74 private final FrameworkSupportModelImpl myModel
;
75 private JPanel myOptionsPanel
;
76 private FrameworksTree myFrameworksTree
;
77 private Set
<String
> myInitializedOptionsPanelIds
= new HashSet
<String
>();
78 private FrameworkSupportNode myLastSelectedNode
;
79 private JLabel myTickCheckboxLabel
;
81 public AddSupportForFrameworksPanel(final List
<FrameworkSupportProvider
> providers
, final @NotNull LibrariesContainer librariesContainer
,
82 @Nullable ModuleBuilder builder
, Computable
<String
> baseDirForLibrariesGetter
) {
83 myLibrariesContainer
= librariesContainer
;
84 myBaseDirForLibrariesGetter
= baseDirForLibrariesGetter
;
85 myProviders
= providers
;
86 myModel
= new FrameworkSupportModelImpl(myLibrariesContainer
.getProject(), builder
);
88 myMirrorsMap
= createMirrorsMap();
90 final Splitter splitter
= new Splitter(false, 0.35f
, 0.1f
, 0.7f
);
91 myFrameworksTree
= new FrameworksTree(myGroups
) {
93 protected void onNodeStateChanged(CheckedTreeNode node
) {
94 if (!(node
instanceof FrameworkSupportNode
)) return;
96 final FrameworkSupportNode frameworkSupportNode
= (FrameworkSupportNode
)node
;
97 frameworkSupportNode
.setConfigurableComponentEnabled(node
.isChecked());
99 myModel
.onFrameworkSelectionChanged(frameworkSupportNode
);
102 myFrameworksTree
.addTreeSelectionListener(new TreeSelectionListener() {
103 public void valueChanged(TreeSelectionEvent e
) {
104 onSelectionChanged();
107 splitter
.setFirstComponent(ScrollPaneFactory
.createScrollPane(myFrameworksTree
));
108 myOptionsPanel
= new JPanel(new CardLayout());
109 myOptionsPanel
.add(EMPTY_CARD
, new JPanel());
110 final JPanel uncheckedLabelPanel
= new JPanel(new BorderLayout());
111 myTickCheckboxLabel
= new JLabel("Tick checkbox");
112 uncheckedLabelPanel
.add(BorderLayout
.NORTH
, myTickCheckboxLabel
);
113 myOptionsPanel
.add(UNCHECKED_CARD
, uncheckedLabelPanel
);
114 splitter
.setSecondComponent(myOptionsPanel
);
115 myFrameworksPanel
.add(splitter
, BorderLayout
.CENTER
);
118 private void onSelectionChanged() {
119 if (!myFrameworksTree
.isProcessingMouseEventOnCheckbox()) {
120 updateOptionsPanel();
123 final FrameworkSupportNode selectedNode
= getSelectedNode();
124 if (!Comparing
.equal(selectedNode
, myLastSelectedNode
)) {
125 applyLibraryOptionsForSelected();
127 myLastSelectedNode
= selectedNode
;
128 if (selectedNode
!= null) {
129 final LibraryCompositionOptionsPanel newOptionsPanel
= selectedNode
.getLibraryCompositionOptionsPanel(myLibrariesContainer
, myMirrorsMap
);
130 if (newOptionsPanel
!= null) {
131 newOptionsPanel
.updateRepositoriesMirrors(myMirrorsMap
);
137 private void applyLibraryOptionsForSelected() {
138 if (myLastSelectedNode
!= null) {
139 final LibraryCompositionOptionsPanel optionsPanel
= myLastSelectedNode
.getLibraryCompositionOptionsPanel(myLibrariesContainer
, myMirrorsMap
);
140 if (optionsPanel
!= null) {
141 optionsPanel
.saveSelectedRepositoriesMirrors(myMirrorsMap
);
142 optionsPanel
.apply();
147 private void updateOptionsPanel() {
148 final FrameworkSupportNode node
= getSelectedNode();
150 if (node
.isChecked()) {
151 initializeOptionsPanel(node
);
152 showCard(node
.getProvider().getId());
155 myTickCheckboxLabel
.setText("Select check box to add '" + node
.getTitle() + "' support");
156 showCard(UNCHECKED_CARD
);
160 showCard(EMPTY_CARD
);
165 private FrameworkSupportNode
getSelectedNode() {
166 final FrameworkSupportNode
[] nodes
= myFrameworksTree
.getSelectedNodes(FrameworkSupportNode
.class, null);
167 return nodes
.length
== 1 ? nodes
[0] : null;
170 private void initializeOptionsPanel(final FrameworkSupportNode node
) {
171 final String id
= node
.getProvider().getId();
172 if (!myInitializedOptionsPanelIds
.contains(id
)) {
173 final JPanel optionsPanel
= new JPanel(new VerticalFlowLayout());
174 JComponent separator
= SeparatorFactory
.createSeparator(node
.getTitle() + " Settings", null);
175 separator
.setBorder(IdeBorderFactory
.createEmptyBorder(0, 0, 5, 5));
177 optionsPanel
.add(separator
);
178 final FrameworkSupportConfigurable configurable
= node
.getConfigurable();
179 optionsPanel
.add(configurable
.getComponent());
180 final JPanel librariesOptionsPanelWrapper
= new JPanel(new BorderLayout());
181 optionsPanel
.add(librariesOptionsPanelWrapper
);
182 configurable
.addListener(new FrameworkSupportConfigurableListener() {
183 public void frameworkVersionChanged() {
184 librariesOptionsPanelWrapper
.removeAll();
185 addLibrariesOptionsPanel(node
, librariesOptionsPanelWrapper
);
186 librariesOptionsPanelWrapper
.revalidate();
189 addLibrariesOptionsPanel(node
, librariesOptionsPanelWrapper
);
190 myOptionsPanel
.add(id
, optionsPanel
);
191 myInitializedOptionsPanelIds
.add(id
);
195 private void addLibrariesOptionsPanel(FrameworkSupportNode node
, JPanel librariesOptionsPanelWrapper
) {
196 final LibraryCompositionOptionsPanel libraryOptionsPanel
= node
.getLibraryCompositionOptionsPanel(myLibrariesContainer
, myMirrorsMap
);
197 if (libraryOptionsPanel
!= null) {
198 librariesOptionsPanelWrapper
.add(BorderLayout
.CENTER
, libraryOptionsPanel
.getMainPanel());
202 private void showCard(String cardName
) {
203 ((CardLayout
)myOptionsPanel
.getLayout()).show(myOptionsPanel
, cardName
);
206 private LibraryDownloadingMirrorsMap
createMirrorsMap() {
207 List
<RemoteRepositoryInfo
> repositoryInfos
= getRemoteRepositories();
208 return new LibraryDownloadingMirrorsMap(repositoryInfos
.toArray(new RemoteRepositoryInfo
[repositoryInfos
.size()]));
211 private List
<RemoteRepositoryInfo
> getRemoteRepositories() {
212 List
<RemoteRepositoryInfo
> repositoryInfos
= new ArrayList
<RemoteRepositoryInfo
>();
213 List
<FrameworkSupportNode
> frameworkNodes
= getFrameworkNodes(false);
214 for (FrameworkSupportNode node
: frameworkNodes
) {
215 LibraryInfo
[] libraries
= node
.getLibraries();
216 for (LibraryInfo library
: libraries
) {
217 LibraryDownloadInfo downloadInfo
= library
.getDownloadingInfo();
218 if (downloadInfo
!= null) {
219 RemoteRepositoryInfo repository
= downloadInfo
.getRemoteRepository();
220 if (repository
!= null) {
221 repositoryInfos
.add(repository
);
226 return repositoryInfos
;
229 private List
<LibraryCompositionSettings
> getLibrariesCompositionSettingsList() {
230 List
<LibraryCompositionSettings
> list
= new ArrayList
<LibraryCompositionSettings
>();
231 List
<FrameworkSupportNode
> selected
= getFrameworkNodes(true);
232 for (FrameworkSupportNode node
: selected
) {
233 final LibraryCompositionSettings settings
= node
.getLibraryCompositionSettings();
234 if (settings
!= null) {
241 public boolean downloadLibraries() {
242 applyLibraryOptionsForSelected();
243 List
<LibraryCompositionSettings
> list
= getLibrariesCompositionSettingsList();
244 for (LibraryCompositionSettings compositionSettings
: list
) {
245 if (!compositionSettings
.downloadFiles(myMirrorsMap
, myLibrariesContainer
, myMainPanel
)) return false;
250 private void createNodes() {
251 Map
<String
, FrameworkSupportNode
> nodes
= new HashMap
<String
, FrameworkSupportNode
>();
252 MultiValuesMap
<String
, FrameworkSupportNode
> groups
= new MultiValuesMap
<String
, FrameworkSupportNode
>(true);
253 for (FrameworkSupportProvider frameworkSupport
: myProviders
) {
254 createNode(frameworkSupport
, nodes
, groups
);
257 myGroups
= new ArrayList
<List
<FrameworkSupportNode
>>();
258 for (String groupId
: groups
.keySet()) {
259 final Collection
<FrameworkSupportNode
> collection
= groups
.get(groupId
);
260 if (collection
!= null) {
261 final List
<FrameworkSupportNode
> group
= new ArrayList
<FrameworkSupportNode
>();
262 for (FrameworkSupportNode node
: collection
) {
263 if (node
.getParentNode() == null) {
267 FrameworkSupportNode
.sortByTitle(group
);
274 private FrameworkSupportNode
createNode(final FrameworkSupportProvider provider
, final Map
<String
, FrameworkSupportNode
> nodes
,
275 final MultiValuesMap
<String
, FrameworkSupportNode
> groups
) {
276 FrameworkSupportNode node
= nodes
.get(provider
.getId());
278 String underlyingFrameworkId
= provider
.getUnderlyingFrameworkId();
279 FrameworkSupportNode parentNode
= null;
280 if (underlyingFrameworkId
!= null) {
281 FrameworkSupportProvider parentProvider
= findProvider(underlyingFrameworkId
);
282 if (parentProvider
== null) {
283 LOG
.info("Cannot find id = " + underlyingFrameworkId
);
286 parentNode
= createNode(parentProvider
, nodes
, groups
);
288 node
= new FrameworkSupportNode(provider
, parentNode
, myModel
, myBaseDirForLibrariesGetter
);
289 nodes
.put(provider
.getId(), node
);
290 groups
.put(provider
.getGroupId(), node
);
296 private FrameworkSupportProvider
findProvider(@NotNull String id
) {
297 for (FrameworkSupportProvider provider
: myProviders
) {
298 if (id
.equals(provider
.getId())) {
302 LOG
.info("Cannot find framework support provider '" + id
+ "'");
306 public JComponent
getMainPanel() {
310 private List
<FrameworkSupportNode
> getFrameworkNodes(final boolean selectedOnly
) {
311 ArrayList
<FrameworkSupportNode
> list
= new ArrayList
<FrameworkSupportNode
>();
312 if (myGroups
!= null) {
313 for (List
<FrameworkSupportNode
> group
: myGroups
) {
314 addChildFrameworks(group
, list
, selectedOnly
);
320 private static void addChildFrameworks(final List
<FrameworkSupportNode
> list
, final List
<FrameworkSupportNode
> result
,
321 final boolean selectedOnly
) {
322 for (FrameworkSupportNode node
: list
) {
323 if (!selectedOnly
|| node
.isChecked()) {
325 addChildFrameworks(node
.getChildren(), result
, selectedOnly
);
330 public void addSupport(final @NotNull Module module
, final @NotNull ModifiableRootModel rootModel
) {
331 List
<Library
> addedLibraries
= new ArrayList
<Library
>();
332 List
<FrameworkSupportNode
> selectedFrameworks
= getFrameworkNodes(true);
333 sortFrameworks(selectedFrameworks
);
335 for (FrameworkSupportNode node
: selectedFrameworks
) {
336 FrameworkSupportConfigurable configurable
= node
.getConfigurable();
337 final LibraryCompositionSettings settings
= node
.getLibraryCompositionSettings();
338 Library library
= settings
!= null ? settings
.addLibraries(rootModel
, addedLibraries
) : null;
339 configurable
.addSupport(module
, rootModel
, library
);
341 for (FrameworkSupportNode node
: selectedFrameworks
) {
342 FrameworkSupportProvider provider
= node
.getProvider();
343 if (provider
instanceof FacetBasedFrameworkSupportProvider
&& !addedLibraries
.isEmpty()) {
344 ((FacetBasedFrameworkSupportProvider
)provider
).processAddedLibraries(module
, addedLibraries
);
349 private void sortFrameworks(final List
<FrameworkSupportNode
> nodes
) {
350 DFSTBuilder
<FrameworkSupportProvider
> builder
= new DFSTBuilder
<FrameworkSupportProvider
>(GraphGenerator
.create(CachingSemiGraph
.create(new ProvidersGraph(myProviders
))));
351 if (!builder
.isAcyclic()) {
352 Pair
<FrameworkSupportProvider
,FrameworkSupportProvider
> pair
= builder
.getCircularDependency();
353 LOG
.error("Circular dependency between providers '" + pair
.getFirst().getId() + "' and '" + pair
.getSecond().getId() + "' was found.");
356 final Comparator
<FrameworkSupportProvider
> comparator
= builder
.comparator();
357 Collections
.sort(nodes
, new Comparator
<FrameworkSupportNode
>() {
358 public int compare(final FrameworkSupportNode o1
, final FrameworkSupportNode o2
) {
359 return comparator
.compare(o1
.getProvider(), o2
.getProvider());
364 private class ProvidersGraph
implements GraphGenerator
.SemiGraph
<FrameworkSupportProvider
> {
365 private final List
<FrameworkSupportProvider
> myFrameworkSupportProviders
;
367 public ProvidersGraph(final List
<FrameworkSupportProvider
> frameworkSupportProviders
) {
368 myFrameworkSupportProviders
= new ArrayList
<FrameworkSupportProvider
>(frameworkSupportProviders
);
371 public Collection
<FrameworkSupportProvider
> getNodes() {
372 return myFrameworkSupportProviders
;
375 public Iterator
<FrameworkSupportProvider
> getIn(final FrameworkSupportProvider provider
) {
376 String
[] ids
= provider
.getPrecedingFrameworkProviderIds();
377 List
<FrameworkSupportProvider
> dependencies
= new ArrayList
<FrameworkSupportProvider
>();
378 String underlyingId
= provider
.getUnderlyingFrameworkId();
379 if (underlyingId
!= null) {
380 FrameworkSupportProvider underlyingProvider
= findProvider(underlyingId
);
381 if (underlyingProvider
!= null) {
382 dependencies
.add(underlyingProvider
);
385 for (String id
: ids
) {
386 FrameworkSupportProvider dependency
= findProvider(id
);
387 if (dependency
!= null) {
388 dependencies
.add(dependency
);
391 return dependencies
.iterator();