View Javadoc

1   package com.atlassian.theplugin.idea.bamboo.build;
2   
3   import com.atlassian.theplugin.commons.bamboo.BambooChangeSet;
4   import com.atlassian.theplugin.commons.bamboo.BambooServerFacade;
5   import com.atlassian.theplugin.commons.bamboo.BambooServerFacadeImpl;
6   import com.atlassian.theplugin.commons.bamboo.BuildDetails;
7   import com.atlassian.theplugin.commons.exception.ServerPasswordNotProvidedException;
8   import com.atlassian.theplugin.commons.remoteapi.RemoteApiException;
9   import com.atlassian.theplugin.idea.Constants;
10  import com.atlassian.theplugin.idea.bamboo.BambooBuildAdapterIdea;
11  import com.atlassian.theplugin.idea.crucible.tree.AtlassianTreeWithToolbar;
12  import com.atlassian.theplugin.idea.crucible.tree.ModelProvider;
13  import com.atlassian.theplugin.idea.ui.tree.AtlassianTreeModel;
14  import com.atlassian.theplugin.idea.ui.tree.file.BambooFileNode;
15  import com.atlassian.theplugin.idea.ui.tree.file.FileTreeModelBuilder;
16  import com.atlassian.theplugin.idea.ui.tree.paneltree.SelectableLabel;
17  import com.atlassian.theplugin.idea.ui.tree.paneltree.TreeUISetup;
18  import com.atlassian.theplugin.util.PluginUtil;
19  import com.intellij.openapi.actionSystem.ActionGroup;
20  import com.intellij.openapi.actionSystem.ActionManager;
21  import com.intellij.openapi.actionSystem.DataProvider;
22  import com.intellij.openapi.progress.ProgressIndicator;
23  import com.intellij.openapi.progress.ProgressManager;
24  import com.intellij.openapi.progress.Task;
25  import com.intellij.openapi.project.Project;
26  import com.intellij.openapi.ui.Splitter;
27  import com.intellij.psi.PsiFile;
28  import org.jetbrains.annotations.NonNls;
29  import org.jetbrains.annotations.NotNull;
30  import org.jetbrains.annotations.Nullable;
31  
32  import javax.swing.*;
33  import javax.swing.event.ListSelectionEvent;
34  import javax.swing.event.ListSelectionListener;
35  import javax.swing.tree.TreePath;
36  import java.awt.*;
37  import java.awt.event.ActionEvent;
38  import java.awt.event.ActionListener;
39  import java.awt.event.MouseAdapter;
40  import java.awt.event.MouseEvent;
41  import java.text.DateFormat;
42  import java.util.List;
43  
44  /**
45   * User: jgorycki
46   * Date: Jan 7, 2009
47   * Time: 12:36:28 PM
48   */
49  public class CommitDetailsPanel extends JPanel implements DataProvider, ActionListener {
50  
51  	private static final float SPLIT_RATIO = 0.6f;
52  	protected static final int ROW_HEIGHT = 16;
53  
54  	private AtlassianTreeWithToolbar fileTree = new AtlassianTreeWithToolbar(TOOLBAR_NAME, (TreeUISetup) null, null);
55  	private final Project project;
56  	private final BambooBuildAdapterIdea build;
57  
58  	private static final String TOOLBAR_NAME = "ThePlugin.Bamboo.CommitListToolBar";
59  
60  	public CommitDetailsPanel(Project project, final BambooBuildAdapterIdea build) {
61  		setLayout(new GridBagLayout());
62  
63  		this.project = project;
64  		this.build = build;
65  
66  		Task.Backgroundable changesTask = new Task.Backgroundable(project, "Retrieving changed files", false) {
67  			@Override
68  			public void run(@NotNull final ProgressIndicator indicator) {
69  				try {
70  					BambooServerFacade bambooFacade = BambooServerFacadeImpl.getInstance(PluginUtil.getLogger());
71  					BuildDetails details = bambooFacade.getBuildDetails(
72  							build.getServer(), build.getPlanKey(), build.getNumber());
73  					final List<BambooChangeSet> commits = details.getCommitInfo();
74  					SwingUtilities.invokeLater(new Runnable() {
75  						public void run() {
76  							fillContent(commits);
77  						}
78  					});
79  				} catch (ServerPasswordNotProvidedException e) {
80  					showError(e);
81  				} catch (RemoteApiException e) {
82  					showError(e);
83  				}
84  			}
85  		};
86  		ProgressManager.getInstance().run(changesTask);
87  	}
88  
89  	public void actionPerformed(ActionEvent e) {
90  		// ignore
91  	}
92  
93  	private void showError(final Exception e) {
94  		SwingUtilities.invokeLater(new Runnable() {
95  			public void run() {
96  				add(new JLabel("Failed to retrieve changed files: " + e.getMessage()));
97  			}
98  		});
99  	}
100 
101 	private class ChangeSetListModel extends DefaultListModel {
102 		public ChangeSetListModel(List<BambooChangeSet> commits) {
103 			int i = 0;
104 			for (BambooChangeSet cs : commits) {
105 				add(i++, cs);
106 			}
107 		}
108 	}
109 
110 	private static final class ChangeSetRendererPanel extends JPanel {
111 
112 		private SelectableLabel comment = new SelectableLabel(true, true, "NOTHING YET", ROW_HEIGHT, false, false);
113 		private SelectableLabel author = new SelectableLabel(true, true, "NOTHING HERE ALSO", ROW_HEIGHT, true, false);
114 		private SelectableLabel date = new SelectableLabel(true, true, "NEITHER HERE", ROW_HEIGHT, false, false);
115 
116 		private ChangeSetRendererPanel() {
117 			setLayout(new GridBagLayout());
118 			GridBagConstraints gbc = new GridBagConstraints();
119 			gbc.weightx = 1.0;
120 			gbc.gridx = 0;
121 			gbc.gridy = 0;
122 			gbc.fill = GridBagConstraints.HORIZONTAL;
123 			add(comment, gbc);
124 			gbc.gridx++;
125 			gbc.weightx = 0.0;
126 			gbc.anchor = GridBagConstraints.LINE_END;
127 			gbc.fill = GridBagConstraints.NONE;
128 			author.setHorizontalAlignment(SwingConstants.RIGHT);
129 			add(author, gbc);
130 			gbc.gridx++;
131 			add(date, gbc);
132 		}
133 
134 		void setChangeSet(BambooChangeSet cs) {
135 			comment.setText(" " + cs.getComment());
136 			author.setText(cs.getAuthor());
137 			DateFormat dfo = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
138 			String commitDate = dfo.format(cs.getCommitDate());
139 			date.setText(", " + commitDate + " ");
140 		}
141 
142 		void setSelected(boolean selected) {
143 			comment.setSelected(selected);
144 			author.setSelected(selected);
145 			date.setSelected(selected);
146 		}
147 	}
148 
149 	private static final ChangeSetRendererPanel CHANGEST_RENDERER_PANEL = new ChangeSetRendererPanel();
150 
151 	private void fillContent(List<BambooChangeSet> commits) {
152 		if (commits == null || commits.size() == 0) {
153 			add(new JLabel("No changes in " + build.getPlanKey() + "-" + build.getBuildNumberAsString()));
154 			return;
155 		}
156 
157 		Splitter split = new Splitter(false, SPLIT_RATIO);
158 		split.setShowDividerControls(true);
159 
160 
161 		JPanel listPanel = new JPanel();
162 		listPanel.setLayout(new BorderLayout());
163 
164 		final JList changesList = new JList() {
165 			@Override
166 			public boolean getScrollableTracksViewportWidth() {
167 				return true;
168 			}
169 		};
170 		changesList.setModel(new ChangeSetListModel(commits));
171 		changesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
172 		changesList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
173 			public void valueChanged(ListSelectionEvent e) {
174 				if (e.getValueIsAdjusting()) {
175 					return;
176 				}
177 				fillFileTree((BambooChangeSet) changesList.getSelectedValue());
178 			}
179 		});
180 		changesList.setCellRenderer(new ListCellRenderer() {
181 			public Component getListCellRendererComponent(JList list, Object value, int index,
182 														  boolean isSelected, boolean cellHasFocus) {
183 				CHANGEST_RENDERER_PANEL.setChangeSet((BambooChangeSet) value);
184 				CHANGEST_RENDERER_PANEL.setSelected(isSelected);
185 				CHANGEST_RENDERER_PANEL.validate();
186 				return CHANGEST_RENDERER_PANEL;
187 			}
188 		});
189 		final JScrollPane scroll = new JScrollPane(changesList, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
190 				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
191 		listPanel.add(scroll, BorderLayout.CENTER);
192 
193 		split.setFirstComponent(listPanel);
194 
195 		JPanel fileTreePanel = new JPanel();
196 		fileTreePanel.setLayout(new BorderLayout());
197 		fileTreePanel.add(new JLabel("Changed Files"), BorderLayout.NORTH);
198 
199 		fileTree.setRootVisible(false);
200 		fileTree.getTreeComponent().addMouseListener(new NavigateToCodeHandler(build.getPlanKey()));
201 		fileTreePanel.add(fileTree, BorderLayout.CENTER);
202 
203 		split.setSecondComponent(fileTreePanel);
204 		split.setShowDividerControls(false);
205 
206 		setLayout(new BorderLayout());
207 		add(split, BorderLayout.CENTER);
208 
209 		if (commits.size() == 1) {
210 			changesList.getSelectionModel().setSelectionInterval(0, 0);
211 		}
212 		validate();
213 	}
214 
215 	@Nullable
216 	public Object getData(@NonNls final String dataId) {
217 		if (dataId.equals(Constants.FILE_TREE)) {
218 			return fileTree;
219 		} else if (dataId.equals(Constants.BUILD_CHANGES_WINDOW)) {
220 			return this;
221 		}
222 		return null;
223 	}
224 
225 	private void fillFileTree(final BambooChangeSet changeSet) {
226 		if (changeSet == null) {
227 			fileTree.setModelProvider(ModelProvider.EMPTY_MODEL_PROVIDER);
228 		} else {
229 			fileTree.setModelProvider(new ModelProvider() {
230 				private AtlassianTreeModel diredModel =
231 						FileTreeModelBuilder.buildTreeModelFromBambooChangeSet(project, changeSet);
232 				private AtlassianTreeModel flatModel =
233 						FileTreeModelBuilder.buildFlatTreeModelFromBambooChangeSet(project, changeSet);
234 
235 				@Override
236 				public AtlassianTreeModel getModel(final AtlassianTreeWithToolbar.State state) {
237 					switch (state) {
238 						case DIRED:
239 							return diredModel;
240 						case FLAT:
241 							return flatModel;
242 						default:
243 							throw new IllegalStateException("Unknown model requested");
244 					}
245 				}
246 			});
247 		}
248 		fileTree.setRootVisible(false);
249 		fileTree.expandAll();
250 	}
251 
252 	private final class NavigateToCodeHandler extends MouseAdapter {
253 
254 		private String place;
255 
256 		private NavigateToCodeHandler(String place) {
257 			this.place = place;
258 		}
259 
260 		@Nullable
261 		private BambooFileNode getBambooFileNode(MouseEvent e) {
262 			final JTree theTree = (JTree) e.getComponent();
263 
264 			TreePath path = theTree.getPathForLocation(e.getX(), e.getY());
265 			if (path == null) {
266 				return null;
267 			}
268 			Object o = path.getLastPathComponent();
269 			if (o instanceof BambooFileNode) {
270 				return (BambooFileNode) o;
271 			}
272 			return null;
273 
274 		}
275 
276 		@Override
277 		public void mouseClicked(MouseEvent e) {
278 			if (e.getClickCount() != 2) {
279 				return;
280 			}
281 
282 			final JTree theTree = (JTree) e.getComponent();
283 
284 			TreePath path = theTree.getPathForLocation(e.getX(), e.getY());
285 			if (path == null) {
286 				return;
287 			}
288 			Object o = path.getLastPathComponent();
289 			if (o instanceof BambooFileNode) {
290 				BambooFileNode bfn = (BambooFileNode) o;
291 				PsiFile psiFile = bfn.getPsiFile();
292 				if (psiFile != null && psiFile.canNavigateToSource()) {
293 					psiFile.navigate(true);
294 				}
295 			}
296 		}
297 
298 
299 		@Override
300 		public void mousePressed(MouseEvent e) {
301 			processPopup(e);
302 		}
303 
304 		@Override
305 		public void mouseReleased(MouseEvent e) {
306 			processPopup(e);
307 		}
308 
309 		public void processPopup(MouseEvent e) {
310 			if (!e.isPopupTrigger()) {
311 				return;
312 			}
313 
314 			final JTree theTree = (JTree) e.getComponent();
315 
316 			TreePath path = theTree.getPathForLocation(e.getX(), e.getY());
317 			if (path == null) {
318 				return;
319 			}
320 			theTree.setSelectionPath(path);
321 
322 
323 			final BambooFileNode bfn = getBambooFileNode(e);
324 			if (bfn == null) {
325 				return;
326 			}
327 
328 
329 			ActionManager aManager = ActionManager.getInstance();
330 			ActionGroup menu = (ActionGroup) aManager.getAction(TOOLBAR_NAME);
331 			if (menu == null) {
332 				return;
333 			}
334 			aManager.createActionPopupMenu(place, menu).getComponent().show(fileTree, e.getX(), e.getY());
335 		}
336 	}
337 }