3eeda23e6c71bc0c165856ba3dbca5469e5a25ad
[idea/community.git] / platform / external-system-impl / src / com / intellij / openapi / externalSystem / service / task / ui / ExternalSystemTasksTreeModel.java
1 /*
2  * Copyright 2000-2013 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.externalSystem.service.task.ui;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.externalSystem.ExternalSystemManager;
20 import com.intellij.openapi.externalSystem.ExternalSystemUiAware;
21 import com.intellij.openapi.externalSystem.model.ProjectSystemId;
22 import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
23 import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
24 import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
25 import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
26 import com.intellij.openapi.externalSystem.service.ui.DefaultExternalSystemUiAware;
27 import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
28 import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
29 import com.intellij.openapi.wm.ToolWindowId;
30 import com.intellij.util.containers.ContainerUtilRt;
31 import gnu.trove.TObjectIntHashMap;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
34
35 import javax.swing.*;
36 import javax.swing.tree.DefaultTreeModel;
37 import javax.swing.tree.TreeNode;
38 import java.util.*;
39
40 /**
41  * @author Denis Zhdanov
42  * @since 5/12/13 10:28 PM
43  */
44 public class ExternalSystemTasksTreeModel extends DefaultTreeModel {
45
46   private static final Logger LOG = Logger.getInstance("#" + ExternalSystemTasksTreeModel.class.getName());
47
48   @NotNull private static final Comparator<TreeNode> NODE_COMPARATOR = new Comparator<TreeNode>() {
49     @Override
50     public int compare(TreeNode t1, TreeNode t2) {
51       Object e1 = ((ExternalSystemNode<?>)t1).getDescriptor().getElement();
52       Object e2 = ((ExternalSystemNode<?>)t2).getDescriptor().getElement();
53       if (e1 instanceof ExternalProjectPojo) {
54         if (e2 instanceof ExternalTaskExecutionInfo) {
55           return 1;
56         }
57         else {
58           return ((ExternalProjectPojo)e1).getName().compareTo(((ExternalProjectPojo)e2).getName());
59         }
60       }
61       else {
62         if (e2 instanceof ExternalProjectPojo) {
63           return -1;
64         }
65         else {
66           return getTaskName((ExternalTaskExecutionInfo)e1).compareTo(getTaskName((ExternalTaskExecutionInfo)e2));
67         }
68       }
69     }
70   };
71
72   @NotNull private final TreeNode[] myNodeHolder  = new TreeNode[1];
73   @NotNull private final int[]      myIndexHolder = new int[1];
74
75   @NotNull private final ExternalSystemUiAware myUiAware;
76   @NotNull private final ProjectSystemId       myExternalSystemId;
77
78   public ExternalSystemTasksTreeModel(@NotNull ProjectSystemId externalSystemId) {
79     super(new ExternalSystemNode<String>(new ExternalSystemNodeDescriptor<String>("", "", null)));
80     myExternalSystemId = externalSystemId;
81     ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
82     if (manager instanceof ExternalSystemUiAware) {
83       myUiAware = (ExternalSystemUiAware)manager;
84     }
85     else {
86       myUiAware = DefaultExternalSystemUiAware.INSTANCE;
87     }
88   }
89
90   private static String getTaskName(@NotNull ExternalTaskExecutionInfo taskInfo) {
91     return taskInfo.getSettings().getTaskNames().get(0);
92   }
93
94   /**
95    * Ensures that current model has a top-level node which corresponds to the given external project info holder
96    *
97    * @param project  target external project info holder
98    */
99   @SuppressWarnings("unchecked")
100   @NotNull
101   public ExternalSystemNode<ExternalProjectPojo> ensureProjectNodeExists(@NotNull ExternalProjectPojo project) {
102     ExternalSystemNode<?> root = getRoot();
103
104     // Remove outdated projects.
105     for (int i = root.getChildCount() - 1; i >= 0; i--) {
106       ExternalSystemNode<?> child = root.getChildAt(i);
107       Object element = child.getDescriptor().getElement();
108       if (element instanceof ExternalProjectPojo
109           && ((ExternalProjectPojo)element).getPath().equals(project.getPath()))
110       {
111         return (ExternalSystemNode<ExternalProjectPojo>)child;
112       }
113     }
114     ExternalProjectPojo element = new ExternalProjectPojo(project.getName(), project.getPath());
115     ExternalSystemNodeDescriptor<ExternalProjectPojo> descriptor = descriptor(element, myUiAware.getProjectIcon());
116     myIndexHolder[0] = root.getChildCount();
117     ExternalSystemNode<ExternalProjectPojo> result = new ExternalSystemNode<ExternalProjectPojo>(descriptor);
118     root.add(result);
119     nodesWereInserted(root, myIndexHolder);
120     return result;
121   }
122
123   public void ensureSubProjectsStructure(@NotNull ExternalProjectPojo topLevelProject,
124                                          @NotNull Collection<ExternalProjectPojo> subProjects)
125   {
126     ExternalSystemNode<ExternalProjectPojo> topLevelProjectNode = ensureProjectNodeExists(topLevelProject);
127     Map<String/*config path*/, ExternalProjectPojo> toAdd = ContainerUtilRt.newHashMap();
128     for (ExternalProjectPojo subProject : subProjects) {
129       toAdd.put(subProject.getPath(), subProject);
130     }
131     toAdd.remove(topLevelProject.getPath());
132
133     final TObjectIntHashMap<Object> taskWeights = new TObjectIntHashMap<Object>();
134     for (int i = 0; i < topLevelProjectNode.getChildCount(); i++) {
135       ExternalSystemNode<?> child = topLevelProjectNode.getChildAt(i);
136       Object childElement = child.getDescriptor().getElement();
137       if (childElement instanceof ExternalTaskExecutionInfo) {
138         taskWeights.put(childElement, subProjects.size() + i);
139         continue;
140       }
141       
142       if (toAdd.remove(((ExternalProjectPojo)childElement).getPath()) == null) {
143         topLevelProjectNode.remove(child);
144         myIndexHolder[0] = i;
145         myNodeHolder[0] = child;
146         nodesWereRemoved(topLevelProjectNode, myIndexHolder, myNodeHolder);
147         //noinspection AssignmentToForLoopParameter
148         i--;
149       }
150     }
151     if (!toAdd.isEmpty()) {
152       for (Map.Entry<String, ExternalProjectPojo> entry : toAdd.entrySet()) {
153         ExternalProjectPojo
154           element = new ExternalProjectPojo(entry.getValue().getName(), entry.getValue().getPath());
155         topLevelProjectNode.add(new ExternalSystemNode<ExternalProjectPojo>(descriptor(element, myUiAware.getProjectIcon())));
156         myIndexHolder[0] = topLevelProjectNode.getChildCount() - 1;
157         nodesWereInserted(topLevelProjectNode, myIndexHolder);
158       }
159     }
160
161     ExternalSystemUiUtil.sort(topLevelProjectNode, this, NODE_COMPARATOR);
162   }
163
164   public void ensureTasks(@NotNull String externalProjectConfigPath, @NotNull Collection<ExternalTaskPojo> tasks) {
165     ExternalSystemNode<ExternalProjectPojo> moduleNode = findProjectNode(externalProjectConfigPath);
166     if (moduleNode == null) {
167       LOG.warn(String.format(
168         "Can't proceed tasks for module which external config path is '%s'. Reason: no such module node is found. Tasks: %s",
169         externalProjectConfigPath, tasks
170       ));
171       return;
172     }
173     Set<ExternalTaskExecutionInfo> toAdd = ContainerUtilRt.newHashSet();
174     for (ExternalTaskPojo task : tasks) {
175       toAdd.add(buildTaskInfo(task));
176     }
177     for (int i = 0; i < moduleNode.getChildCount(); i++) {
178       ExternalSystemNode<?> childNode = moduleNode.getChildAt(i);
179       Object element = childNode.getDescriptor().getElement();
180       if (element instanceof ExternalTaskExecutionInfo) {
181         if (!toAdd.remove(element)) {
182           moduleNode.remove(childNode);
183           myIndexHolder[0] = i;
184           myNodeHolder[0] = childNode;
185           nodesWereRemoved(moduleNode, myIndexHolder, myNodeHolder);
186         }
187       }
188     }
189     
190     if (!toAdd.isEmpty()) {
191       for (ExternalTaskExecutionInfo taskInfo : toAdd) {
192         moduleNode.add(new ExternalSystemNode<ExternalTaskExecutionInfo>(descriptor(taskInfo, myUiAware.getTaskIcon())));
193         myIndexHolder[0] = moduleNode.getChildCount() - 1;
194         nodesWereInserted(moduleNode, myIndexHolder);
195       }
196     }
197     ExternalSystemUiUtil.sort(moduleNode, this, NODE_COMPARATOR);
198   }
199
200   @NotNull
201   private ExternalTaskExecutionInfo buildTaskInfo(@NotNull ExternalTaskPojo task) {
202     ExternalSystemTaskExecutionSettings settings = new ExternalSystemTaskExecutionSettings();
203     settings.setExternalProjectPath(task.getLinkedExternalProjectPath());
204     settings.setTaskNames(Collections.singletonList(task.getName()));
205     settings.setExternalSystemIdString(myExternalSystemId.toString());
206     return new ExternalTaskExecutionInfo(settings, ToolWindowId.RUN);
207   }
208
209   @SuppressWarnings("unchecked")
210   @Nullable
211   private ExternalSystemNode<ExternalProjectPojo> findProjectNode(@NotNull String configPath) {
212     for (int i = getRoot().getChildCount() - 1; i >= 0; i--) {
213       ExternalSystemNode<?> child = getRoot().getChildAt(i);
214       Object childElement = child.getDescriptor().getElement();
215       if (childElement instanceof ExternalProjectPojo && ((ExternalProjectPojo)childElement).getPath().equals(configPath)) {
216         return (ExternalSystemNode<ExternalProjectPojo>)child;
217       }
218       for (int j = child.getChildCount() - 1; j >= 0; j--) {
219         ExternalSystemNode<?> grandChild = child.getChildAt(j);
220         Object grandChildElement = grandChild.getDescriptor().getElement();
221         if (grandChildElement instanceof ExternalProjectPojo
222             && ((ExternalProjectPojo)grandChildElement).getPath().equals(configPath))
223         {
224           return (ExternalSystemNode<ExternalProjectPojo>)grandChild;
225         }
226       }
227     }
228     return null;
229   }
230
231   @NotNull
232   private static <T> ExternalSystemNodeDescriptor<T> descriptor(@NotNull T element, @Nullable Icon icon) {
233     return new ExternalSystemNodeDescriptor<T>(element, element.toString(), icon);
234   }
235   
236   @NotNull
237   public ExternalSystemNode<?> getRoot() {
238     return (ExternalSystemNode<?>)super.getRoot();
239   }
240 }