View Javadoc

1   /**
2    * Copyright (C) 2008 Atlassian
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  
17  package com.atlassian.theplugin.idea.ui.tree.file;
18  
19  import com.atlassian.theplugin.commons.BambooFileInfo;
20  import com.atlassian.theplugin.commons.VersionedFileInfo;
21  import com.atlassian.theplugin.commons.bamboo.BambooChangeSet;
22  import com.atlassian.theplugin.commons.crucible.api.model.CrucibleFileInfo;
23  import com.atlassian.theplugin.idea.IdeaHelper;
24  import com.atlassian.theplugin.idea.crucible.ReviewData;
25  import com.atlassian.theplugin.idea.crucible.comments.CrucibleReviewActionListener;
26  import com.atlassian.theplugin.idea.crucible.comments.ReviewActionEventBroker;
27  import com.atlassian.theplugin.idea.crucible.events.FocusOnFileComments;
28  import com.atlassian.theplugin.idea.crucible.events.FocusOnGeneralComments;
29  import com.atlassian.theplugin.idea.crucible.events.ShowFileEvent;
30  import com.atlassian.theplugin.idea.ui.tree.AtlassianClickAction;
31  import com.atlassian.theplugin.idea.ui.tree.AtlassianTreeModel;
32  import com.atlassian.theplugin.idea.ui.tree.AtlassianTreeNode;
33  import com.atlassian.theplugin.util.CodeNavigationUtil;
34  import com.intellij.openapi.project.Project;
35  import com.intellij.psi.PsiFile;
36  import com.intellij.psi.PsiManager;
37  import org.jetbrains.annotations.Nullable;
38  
39  import java.util.ArrayList;
40  import java.util.List;
41  
42  public final class FileTreeModelBuilder {
43  
44  	private FileTreeModelBuilder() {
45  		// this is a utility class
46  	}
47  
48  	public static AtlassianTreeModel buildTreeModelFromBambooChangeSet(Project project, BambooChangeSet changeSet) {
49  		FileNode root = new FolderNode("/");
50  		FileTreeModel model = new FileTreeModel(root);
51  		for (BambooFileInfo f : changeSet.getFiles()) {
52  			model.addFile(project, root, f);
53  		}
54  		model.compactModel(model.getRoot());
55  		return model;
56  	}
57  
58  	@Nullable
59  	private static PsiFile guessCorrespondingPsiFile(final Project project, BambooFileInfo file) {
60  		final PsiFile[] psifiles = PsiManager.getInstance(project).getShortNamesCache().getFilesByName(
61  				file.getFileDescriptor().getName());
62  		return CodeNavigationUtil.guessMatchingFile(file.getFileDescriptor().getUrl(), psifiles, project.getBaseDir());
63  	}
64  
65  	public static AtlassianTreeModel buildFlatTreeModelFromBambooChangeSet(final Project project, BambooChangeSet changeSet) {
66  		FileTreeModel model = new FileTreeModel(new FolderNode("/"));
67  		for (BambooFileInfo f : changeSet.getFiles()) {
68  			PsiFile psiFile = guessCorrespondingPsiFile(project, f);
69  			model.getRoot().addChild(new BambooFileNode(f, psiFile));
70  		}
71  		return model;
72  	}
73  
74  
75  	public static AtlassianTreeModel buildFlatModelFromCrucibleChangeSet(final Project project, final ReviewData review,
76  			List<CrucibleFileInfo> files) {
77  		AtlassianTreeModel model = new FileTreeModel(new CrucibleChangeSetTitleNode(review, new AtlassianClickAction() {
78  			public void execute(AtlassianTreeNode node, int noOfClicks) {
79  				switch (noOfClicks) {
80  					case 1:
81  					case 2:
82  						ReviewActionEventBroker broker = IdeaHelper.getReviewActionEventBroker(project);
83  						broker.trigger(new FocusOnGeneralComments(CrucibleReviewActionListener.ANONYMOUS, review));
84  						break;
85  					default:
86  				}
87  			}
88  		}));
89  		for (final CrucibleFileInfo file : files) {
90  			//according to filter show only "proper files"
91  			CrucibleFileNode childNode = new CrucibleFileNode(review, file, new AtlassianClickAction() {
92  				public void execute(AtlassianTreeNode node, int noOfClicks) {
93  					ReviewActionEventBroker broker = IdeaHelper.getReviewActionEventBroker(project);
94  					switch (noOfClicks) {
95  						case 1:
96  							broker.trigger(
97  									new FocusOnFileComments(CrucibleReviewActionListener.ANONYMOUS, review, file));
98  							break;
99  						case 2:
100 							broker.trigger(new ShowFileEvent(CrucibleReviewActionListener.ANONYMOUS, review, file));
101 							break;
102 						default:
103 							break;
104 					}
105 				}
106 			});
107 
108 			model.getRoot().addNode(childNode);
109 
110 		}
111 		return model;
112 	}
113 
114 	public static AtlassianTreeModel buildTreeModelFromCrucibleChangeSet(final Project project, final ReviewData review,
115 			final List<CrucibleFileInfo> files) {
116 		FileNode root = new CrucibleChangeSetTitleNode(review, new AtlassianClickAction() {
117 			public void execute(AtlassianTreeNode node, int noOfClicks) {
118 				switch (noOfClicks) {
119 					case 1:
120 					case 2:
121 						ReviewActionEventBroker broker = IdeaHelper.getReviewActionEventBroker(project);
122 						broker.trigger(new FocusOnGeneralComments(CrucibleReviewActionListener.ANONYMOUS, review));
123 						break;
124 					default:
125 				}
126 			}
127 		});
128 		FileTreeModel model = new FileTreeModel(root);
129 		for (final CrucibleFileInfo f : files) {
130 			//according to filter show only "proper files"
131 			CrucibleFileNode childNode = new CrucibleFileNode(review, f, new AtlassianClickAction() {
132 				public void execute(AtlassianTreeNode node, int noOfClicks) {
133 					ReviewActionEventBroker broker = IdeaHelper.getReviewActionEventBroker(project);
134 					switch (noOfClicks) {
135 						case 1:
136 							broker.trigger(new FocusOnFileComments(CrucibleReviewActionListener.ANONYMOUS, review, f));
137 							break;
138 						case 2:
139 							broker.trigger(new ShowFileEvent(CrucibleReviewActionListener.ANONYMOUS, review, f));
140 							break;
141 						default:
142 							break;
143 					}
144 				}
145 			});
146 
147 				FileNode node = model.createPlace(root, f);
148 				// todo lguminski to avoid creation of a new object for each node
149 				node.addChild(childNode);
150 
151 		}
152 		model.compactModel(model.getRoot());
153 		return model;
154 		//return model;
155 
156 	}
157 
158 	private static class FileTreeModel extends AtlassianTreeModel {
159 		public FileTreeModel(FileNode root) {
160 			super(root);
161 		}
162 
163 		@Override
164 		public FileNode getRoot() {
165 			return (FileNode) super.getRoot();
166 		}
167 
168 		public void addFile(Project project, FileNode root, BambooFileInfo file) {
169 			PsiFile psiFile = guessCorrespondingPsiFile(project, file);
170 			FileNode node = createPlace(root, file);
171 			node.addChild(new BambooFileNode(file, AtlassianClickAction.EMPTY_ACTION, psiFile));
172 		}
173 
174 		private FileNode createPlace(FileNode root, VersionedFileInfo file) {
175 			int idx = 0;
176 			String fileName = file.getFileDescriptor().getUrl();
177 			FileNode node = root;
178 			do {
179 				int newIdx = fileName.indexOf('/', idx);
180 				if (newIdx != -1) {
181 					String newNodeName = fileName.substring(idx, newIdx);
182 					if (newNodeName.length() > 0) {
183 						if (!node.hasNode(newNodeName)) {
184 							FileNode newNode = new FolderNode(newNodeName);
185 							node.addChild(newNode);
186 							node = newNode;
187 						} else {
188 							node = node.getNode(newNodeName);
189 						}
190 					}
191 				}
192 				idx = newIdx + 1;
193 			} while (idx > 0);
194 			return node;
195 		}
196 
197 		private void compactModel(FileNode node) {
198 			if (node.isLeaf()) {
199 				return;
200 			}
201 
202 			java.util.List<FileNode> ch = new ArrayList<FileNode>();
203 
204 			for (FileNode n : node.getChildren().values()) {
205 				ch.add(n);
206 			}
207 
208 			node.removeChildren();
209 
210 			for (FileNode n : ch) {
211 				compactModel(n);
212 				if (n.getChildCount() == 1) {
213 					FileNode cn = (FileNode) n.getFirstChild();
214 					if (!cn.isLeaf()) {
215 						String newName = n.getName() + "/" + cn.getName();
216 						cn.setName(newName);
217 						node.addChild(cn);
218 					} else {
219 						node.addChild(n);
220 					}
221 				} else {
222 					node.addChild(n);
223 				}
224 			}
225 		}
226 
227 	}
228 }