1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.theplugin.idea.bamboo;
18
19 import com.atlassian.theplugin.commons.bamboo.BambooChangeSet;
20 import com.atlassian.theplugin.idea.Constants;
21 import com.atlassian.theplugin.idea.TableColumnInfo;
22 import com.atlassian.theplugin.idea.crucible.tree.AtlassianTreeWithToolbar;
23 import com.atlassian.theplugin.idea.crucible.tree.ModelProvider;
24 import com.atlassian.theplugin.idea.ui.AtlassianTableView;
25 import com.atlassian.theplugin.idea.ui.TableColumnProvider;
26 import com.atlassian.theplugin.idea.ui.TableItemSelectedListener;
27 import com.atlassian.theplugin.idea.ui.tree.AtlassianTreeModel;
28 import com.atlassian.theplugin.idea.ui.tree.file.BambooFileNode;
29 import com.atlassian.theplugin.idea.ui.tree.file.FileTreeModelBuilder;
30 import com.intellij.openapi.actionSystem.ActionGroup;
31 import com.intellij.openapi.actionSystem.ActionManager;
32 import com.intellij.openapi.actionSystem.DataProvider;
33 import com.intellij.openapi.project.Project;
34 import com.intellij.openapi.ui.Splitter;
35 import com.intellij.openapi.wm.ToolWindow;
36 import com.intellij.openapi.wm.ToolWindowAnchor;
37 import com.intellij.openapi.wm.ToolWindowManager;
38 import com.intellij.peer.PeerFactory;
39 import com.intellij.psi.PsiFile;
40 import com.intellij.ui.content.Content;
41 import com.intellij.util.ui.ListTableModel;
42 import org.jetbrains.annotations.NonNls;
43 import org.jetbrains.annotations.Nullable;
44
45 import javax.swing.*;
46 import javax.swing.table.TableCellRenderer;
47 import javax.swing.tree.TreePath;
48 import java.awt.*;
49 import java.awt.event.MouseAdapter;
50 import java.awt.event.MouseEvent;
51 import java.util.Comparator;
52 import java.util.Date;
53 import java.util.HashMap;
54 import java.util.List;
55
56 public final class BuildChangesToolWindow {
57 private final Project project;
58
59
60 public interface ChangesTree {
61 boolean GROUP_BY_DIRECTORY_DEFAULT = true;
62
63 void showDiff();
64
65 void showDiffWithLocal();
66
67 void showRepositoryVersion();
68 }
69
70 private static final String TOOL_WINDOW_TITLE = "Bamboo Build Changes";
71
72 private HashMap<String, CommitDetailsPanel> panelMap = new HashMap<String, CommitDetailsPanel>();
73
74 public BuildChangesToolWindow(Project project) {
75 this.project = project;
76
77
78
79 }
80
81 public ChangesTree getChangesTree(String name) {
82 return panelMap.get(name);
83 }
84
85 public void showBuildChanges(String buildKey, String buildNumber, List<BambooChangeSet> commits) {
86 String contentKey = buildKey + "-" + buildNumber;
87
88
89 ToolWindowManager twm = ToolWindowManager.getInstance(project);
90 ToolWindow commitDetailsToolWindow = twm.getToolWindow(TOOL_WINDOW_TITLE);
91 if (commitDetailsToolWindow == null) {
92 commitDetailsToolWindow = twm.registerToolWindow(TOOL_WINDOW_TITLE, true, ToolWindowAnchor.BOTTOM);
93 commitDetailsToolWindow.setIcon(Constants.BAMBOO_COMMITS_ICON);
94 }
95
96 Content content = commitDetailsToolWindow.getContentManager().findContent(contentKey);
97
98 if (content == null) {
99 CommitDetailsPanel detailsPanel = new CommitDetailsPanel(project, contentKey, commits);
100 panelMap.remove(contentKey);
101 panelMap.put(contentKey, detailsPanel);
102
103 PeerFactory peerFactory = PeerFactory.getInstance();
104 content = peerFactory.getContentFactory().createContent(detailsPanel, contentKey, true);
105 content.setIcon(Constants.BAMBOO_COMMITS_ICON);
106 content.putUserData(com.intellij.openapi.wm.ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
107 commitDetailsToolWindow.getContentManager().addContent(content);
108 }
109
110 commitDetailsToolWindow.getContentManager().setSelectedContent(content);
111 commitDetailsToolWindow.show(null);
112 }
113
114 private static class CommitDetailsPanel extends JPanel implements ChangesTree, DataProvider {
115 private static final float SPLIT_RATIO = 0.6f;
116 private AtlassianTreeWithToolbar fileTree = new AtlassianTreeWithToolbar(TOOLBAR_NAME);
117 private final Project project;
118
119 private String name;
120 private static final String TOOLBAR_NAME = "ThePlugin.Bamboo.CommitListToolBar";
121
122 public CommitDetailsPanel(Project project, String name, final List<BambooChangeSet> commits) {
123 this.project = project;
124 this.name = name;
125
126 if (commits == null || commits.size() == 0) {
127 add(new JLabel("No commits in " + name));
128 return;
129 }
130
131 setLayout(new GridBagLayout());
132
133 Splitter split = new Splitter(false, SPLIT_RATIO);
134 split.setShowDividerControls(true);
135
136
137 JPanel tablePanel = new JPanel();
138 tablePanel.setLayout(new BorderLayout());
139 final AtlassianTableView<BambooChangeSet> commitsTable = createCommitsTable(commits);
140 tablePanel.add(new JScrollPane(commitsTable), BorderLayout.CENTER);
141
142 split.setFirstComponent(tablePanel);
143
144 JPanel fileTreePanel = new JPanel();
145 fileTreePanel.setLayout(new BorderLayout());
146
147 JLabel label = new JLabel("Changed Files");
148 fileTreePanel.add(label, BorderLayout.NORTH);
149
150 fileTree.setRootVisible(false);
151 fileTreePanel.add(fileTree, BorderLayout.CENTER);
152
153 split.setSecondComponent(fileTreePanel);
154
155 setLayout(new BorderLayout());
156 add(split, BorderLayout.CENTER);
157 }
158
159 @Nullable
160 public Object getData(@NonNls final String dataId) {
161 if (dataId.equals(Constants.FILE_TREE)) {
162 return fileTree;
163 } else if (dataId.equals(Constants.BUILD_CHANGES_WINDOW)) {
164 return this;
165 }
166 return null;
167 }
168
169
170 private static class AuthorColumn extends TableColumnInfo<BambooChangeSet, String> {
171 private static final int PREFERRED_WIDTH = 100;
172
173 @Override
174 public String getColumnName() {
175 return "Author";
176 }
177
178 @Override
179 public Class getColumnClass() {
180 return String.class;
181 }
182
183 @Override
184 public int getPrefferedWidth() {
185 return PREFERRED_WIDTH;
186 }
187
188 @Override
189 public String valueOf(final BambooChangeSet obj) {
190 return obj.getAuthor();
191 }
192
193 @Override
194 public Comparator<BambooChangeSet> getComparator() {
195 return new Comparator<BambooChangeSet>() {
196 public int compare(BambooChangeSet o, BambooChangeSet o1) {
197 return o.getAuthor().compareTo(o1.getAuthor());
198 }
199 };
200 }
201
202 }
203
204 private static class DateColumn extends TableColumnInfo<BambooChangeSet, Date> {
205 private static final int PREFERRED_WIDTH = 100;
206
207 @Override
208 public String getColumnName() {
209 return "Date";
210 }
211
212 @Override
213 public Class getColumnClass() {
214 return Date.class;
215 }
216
217 @Override
218 public int getPrefferedWidth() {
219 return PREFERRED_WIDTH;
220 }
221
222 @Override
223 public Date valueOf(BambooChangeSet o) {
224 return o.getCommitDate();
225 }
226
227 @Override
228 public Comparator<BambooChangeSet> getComparator() {
229 return new Comparator<BambooChangeSet>() {
230 public int compare(BambooChangeSet o, BambooChangeSet o1) {
231 return o1.getCommitDate().compareTo(o.getCommitDate());
232 }
233 };
234 }
235 }
236
237 private static class CommentColumn extends TableColumnInfo<BambooChangeSet, String> {
238 private static final int PREFERRED_WIDTH = 600;
239
240 @Override
241 public String getColumnName() {
242 return "Comment";
243 }
244
245 @Override
246 public Class getColumnClass() {
247 return String.class;
248 }
249
250 @Override
251 public int getPrefferedWidth() {
252 return PREFERRED_WIDTH;
253 }
254
255 @Override
256 public String valueOf(BambooChangeSet o) {
257 return o.getComment();
258 }
259
260 @Override
261 public Comparator<BambooChangeSet> getComparator() {
262 return new Comparator<BambooChangeSet>() {
263 public int compare(BambooChangeSet o, BambooChangeSet o1) {
264 return o.getComment().compareTo(o1.getComment());
265 }
266 };
267 }
268 }
269
270 private AtlassianTableView<BambooChangeSet> createCommitsTable(final List<BambooChangeSet> commits) {
271 TableColumnProvider prov = new TableColumnProvider() {
272 public TableColumnInfo[] makeColumnInfo() {
273 return new TableColumnInfo[]{new AuthorColumn(), new DateColumn(), new CommentColumn()};
274 }
275
276 public TableCellRenderer[] makeRendererInfo() {
277 return new TableCellRenderer[]{null, null, null};
278 }
279 };
280 final AtlassianTableView<BambooChangeSet> atv = new AtlassianTableView<BambooChangeSet>(prov,
281 new ListTableModel<BambooChangeSet>(prov.makeColumnInfo(), commits, 0), null);
282 atv.addItemSelectedListener(new TableItemSelectedListener<BambooChangeSet>() {
283 public void itemSelected(AtlassianTableView<BambooChangeSet> table, int noClicks) {
284 final BambooChangeSet c = table.getSelectedObject();
285 if (c == null) {
286 fileTree.setModelProvider(ModelProvider.EMPTY_MODEL_PROVIDER);
287 } else {
288 fileTree.setModelProvider(new ModelProvider() {
289 private AtlassianTreeModel diredModel =
290 FileTreeModelBuilder.buildTreeModelFromBambooChangeSet(project, c);
291 private AtlassianTreeModel flatModel =
292 FileTreeModelBuilder.buildFlatTreeModelFromBambooChangeSet(project, c);
293
294 @Override
295 public AtlassianTreeModel getModel(final AtlassianTreeWithToolbar.STATE state) {
296 switch (state) {
297 case DIRED:
298 return diredModel;
299 case FLAT:
300 return flatModel;
301 default:
302 throw new IllegalStateException("Unknown model requested");
303 }
304 }
305 });
306 }
307 fileTree.setRootVisible(false);
308 fileTree.expandAll();
309 fileTree.getTreeComponent().addMouseListener(new NavigateToCodeHandler(name));
310 }
311 });
312 return atv;
313 }
314
315 public void showDiff() {
316
317 }
318
319 public void showDiffWithLocal() {
320
321 }
322
323 public void showRepositoryVersion() {
324
325 }
326
327 private static final class NavigateToCodeHandler extends MouseAdapter {
328
329 private String place;
330
331 private NavigateToCodeHandler(String place) {
332 this.place = place;
333 }
334
335 @Nullable
336 private BambooFileNode getBambooFileNode(MouseEvent e) {
337 final JTree theTree = (JTree) e.getComponent();
338
339 TreePath path = theTree.getPathForLocation(e.getX(), e.getY());
340 if (path == null) {
341 return null;
342 }
343 Object o = path.getLastPathComponent();
344 if (o instanceof BambooFileNode) {
345 return (BambooFileNode) o;
346 }
347 return null;
348
349 }
350
351 @Override
352 public void mouseClicked(MouseEvent e) {
353 if (e.getClickCount() != 2) {
354 return;
355 }
356
357 final JTree theTree = (JTree) e.getComponent();
358
359 TreePath path = theTree.getPathForLocation(e.getX(), e.getY());
360 if (path == null) {
361 return;
362 }
363 Object o = path.getLastPathComponent();
364 if (o instanceof BambooFileNode) {
365 BambooFileNode bfn = (BambooFileNode) o;
366 PsiFile psiFile = bfn.getPsiFile();
367 if (psiFile != null && psiFile.canNavigateToSource() == true) {
368 psiFile.navigate(true);
369 }
370 }
371 }
372
373
374 @Override
375 public void mousePressed(MouseEvent e) {
376 processPopup(e);
377 }
378
379 @Override
380 public void mouseReleased(MouseEvent e) {
381 processPopup(e);
382 }
383
384 public void processPopup(MouseEvent e) {
385 if (e.isPopupTrigger() == false) {
386 return;
387 }
388
389 final JTree theTree = (JTree) e.getComponent();
390
391 TreePath path = theTree.getPathForLocation(e.getX(), e.getY());
392 if (path == null) {
393 return;
394 }
395 theTree.setSelectionPath(path);
396
397
398 final BambooFileNode bfn = getBambooFileNode(e);
399 if (bfn == null) {
400 return;
401 }
402
403
404 ActionManager aManager = ActionManager.getInstance();
405 ActionGroup menu = (ActionGroup) aManager.getAction(TOOLBAR_NAME);
406 if (menu == null) {
407 return;
408 }
409 aManager.createActionPopupMenu(place, menu).getComponent().show(e.getComponent(), e.getX(), e.getY());
410
411 }
412
413 }
414 }
415 }