1 package git4idea
.checkin
;
3 import com
.intellij
.openapi
.progress
.ProgressManager
;
4 import com
.intellij
.openapi
.project
.Project
;
5 import com
.intellij
.openapi
.ui
.DialogWrapper
;
6 import com
.intellij
.openapi
.ui
.Messages
;
7 import com
.intellij
.openapi
.vcs
.VcsException
;
8 import com
.intellij
.openapi
.vfs
.VirtualFile
;
9 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
10 import git4idea
.GitBranch
;
11 import git4idea
.GitRevisionNumber
;
12 import git4idea
.actions
.GitShowAllSubmittedFilesAction
;
13 import git4idea
.commands
.*;
14 import git4idea
.i18n
.GitBundle
;
17 import javax
.swing
.event
.TreeSelectionEvent
;
18 import javax
.swing
.event
.TreeSelectionListener
;
19 import javax
.swing
.tree
.DefaultMutableTreeNode
;
20 import javax
.swing
.tree
.DefaultTreeModel
;
21 import javax
.swing
.tree
.TreeNode
;
22 import javax
.swing
.tree
.TreePath
;
23 import java
.awt
.event
.ActionEvent
;
24 import java
.awt
.event
.ActionListener
;
25 import java
.util
.ArrayList
;
26 import java
.util
.Collection
;
27 import java
.util
.Date
;
28 import java
.util
.List
;
31 * The dialog that allows pushing active branches.
33 public class GitPushActiveBranchesDialog
extends DialogWrapper
{
35 * Amount of digits to show in commit prefix
37 private final static int HASH_PREFIX_SIZE
= 8;
39 * The view commit button
41 private JButton myViewButton
;
45 private JPanel myPanel
;
47 * The commit tree control
49 private JTree myCommitTree
;
51 * The root information structure
53 private List
<Root
> myRoots
;
58 * @param project the project
59 * @param roots the loaded roots
61 private GitPushActiveBranchesDialog(final Project project
, List
<Root
> roots
) {
64 myCommitTree
.setModel(new DefaultTreeModel(createTree()));
65 TreeUtil
.expandAll(myCommitTree
);
66 for (Root r
: roots
) {
67 if (r
.branch
== null) {
68 setErrorText(GitBundle
.getString("push.active.error.no.branch"));
69 setOKActionEnabled(false);
72 if (r
.remoteCommits
!= 0) {
73 setErrorText(GitBundle
.getString("push.active.error.behind"));
74 setOKActionEnabled(false);
78 myCommitTree
.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
79 public void valueChanged(TreeSelectionEvent e
) {
80 TreePath path
= myCommitTree
.getSelectionModel().getSelectionPath();
82 myViewButton
.setEnabled(false);
85 DefaultMutableTreeNode node
= (DefaultMutableTreeNode
)path
.getLastPathComponent();
86 myViewButton
.setEnabled(node
!= null && myCommitTree
.getSelectionCount() == 1 && node
.getUserObject() instanceof Commit
);
89 myViewButton
.addActionListener(new ActionListener() {
90 public void actionPerformed(ActionEvent e
) {
91 TreePath path
= myCommitTree
.getSelectionModel().getSelectionPath();
95 DefaultMutableTreeNode node
= (DefaultMutableTreeNode
)path
.getLastPathComponent();
96 if (node
== null || !(node
.getUserObject() instanceof Commit
)) {
99 Commit c
= (Commit
)node
.getUserObject();
100 GitShowAllSubmittedFilesAction
.showSubmittedFiles(project
, c
.revision
.asString(), c
.root
.root
);
103 setTitle(GitBundle
.getString("push.active.title"));
104 setOKButtonText(GitBundle
.getString("push.active.button"));
109 * @return the created tree
111 private TreeNode
createTree() {
112 DefaultMutableTreeNode treeRoot
= new DefaultMutableTreeNode("ROOT", true);
113 for (Root r
: myRoots
) {
114 DefaultMutableTreeNode rootNode
= new DefaultMutableTreeNode(r
, true);
115 Status status
= new Status();
117 rootNode
.add(new DefaultMutableTreeNode(status
, false));
118 for (Commit c
: r
.commits
) {
119 rootNode
.add(new DefaultMutableTreeNode(c
, false));
121 treeRoot
.add(rootNode
);
131 protected JComponent
createCenterPanel() {
139 protected String
getDimensionServiceKey() {
140 return getClass().getName();
146 * @param project the project
147 * @param roots the VCS root list
148 * @return the loaded information about vcs roots
150 static List
<Root
> loadRoots(final Project project
, final List
<VirtualFile
> roots
, final Collection
<VcsException
> exceptions
) {
151 final ProgressManager manager
= ProgressManager
.getInstance();
152 final ArrayList
<Root
> rc
= new ArrayList
<Root
>();
153 manager
.runProcessWithProgressSynchronously(new Runnable() {
155 for (VirtualFile root
: roots
) {
160 GitBranch b
= GitBranch
.current(project
, root
);
162 r
.branch
= b
.getFullName();
163 r
.remote
= b
.getTrackedRemoteName(project
, root
);
164 r
.remoteBranch
= b
.getTrackedBranchName(project
, root
);
165 if (r
.remote
!= null) {
166 if(!r
.remote
.equals(".")) {
167 GitLineHandler fetch
= new GitLineHandler(project
, root
, GitHandler
.FETCH
);
168 fetch
.addParameters(r
.remote
, "-v");
169 Collection
<VcsException
> exs
= GitHandlerUtil
.doSynchronouslyWithExceptions(fetch
);
170 exceptions
.addAll(exs
);
172 GitBranch tracked
= b
.tracked(project
, root
);
173 assert tracked
!= null : "Tracked branch cannot be null here";
174 GitSimpleHandler unmerged
= new GitSimpleHandler(project
, root
, GitHandler
.LOG
);
175 unmerged
.addParameters("--pretty=format:%H", r
.branch
+ ".." + tracked
.getFullName());
176 unmerged
.setNoSSH(true);
177 unmerged
.setStdoutSuppressed(true);
178 StringScanner su
= new StringScanner(unmerged
.run());
179 while (su
.hasMoreData()) {
180 if (su
.line().trim().length() != 0) {
184 GitSimpleHandler toPush
= new GitSimpleHandler(project
, root
, GitHandler
.LOG
);
185 toPush
.addParameters("--pretty=format:%H%x20%ct%x20%s", tracked
.getFullName() + ".." + r
.branch
);
186 toPush
.setNoSSH(true);
187 toPush
.setStdoutSuppressed(true);
188 StringScanner sp
= new StringScanner(toPush
.run());
189 while (sp
.hasMoreData()) {
194 Commit c
= new Commit();
196 String hash
= sp
.spaceToken();
197 String time
= sp
.spaceToken();
198 c
.revision
= new GitRevisionNumber(hash
, new Date(Long
.parseLong(time
) * 1000L));
199 c
.message
= sp
.line();
205 catch (VcsException e
) {
210 }, GitBundle
.getString("push.active.fetching"), false, project
);
217 * @param project the context project
218 * @param vcsRoots the vcs roots in the project
219 * @param exceptions the collected exceptions
221 public static void showDialog(final Project project
, List
<VirtualFile
> vcsRoots
, final Collection
<VcsException
> exceptions
) {
222 final List
<Root
> roots
= loadRoots(project
, vcsRoots
, exceptions
);
223 if (!exceptions
.isEmpty()) {
225 .showErrorDialog(project
, GitBundle
.getString("push.active.fetch.failed"), GitBundle
.getString("push.active.fetch.failed.title"));
228 GitPushActiveBranchesDialog d
= new GitPushActiveBranchesDialog(project
, roots
);
231 final ProgressManager manager
= ProgressManager
.getInstance();
232 manager
.runProcessWithProgressSynchronously(new Runnable() {
234 for (Root r
: roots
) {
235 if (r
.remote
!= null && r
.commits
.size() != 0) {
236 GitLineHandler h
= new GitLineHandler(project
, r
.root
, GitHandler
.PUSH
);
237 h
.addParameters("-v", r
.remote
, r
.branch
+":"+r
.remoteBranch
);
238 GitHandlerUtil
.doSynchronouslyWithExceptions(h
);
242 }, GitBundle
.getString("push.active.pushing"), false, project
);
248 * The commit descriptor
250 static class Status
{
260 public String
toString() {
261 if (root
.commits
.size() == 0) {
262 return GitBundle
.message("push.active.status.no.commits");
264 if (root
.remoteCommits
!= 0) {
265 return GitBundle
.message("push.active.status.behind", root
.remoteCommits
);
267 if (root
.branch
== null) {
268 return GitBundle
.message("push.active.status.no.branch");
270 if (root
.remote
== null) {
271 return GitBundle
.message("push.active.status.no.tracked");
273 return GitBundle
.message("push.active.status.push", root
.commits
.size());
278 * The commit descriptor
280 static class Commit
{
288 GitRevisionNumber revision
;
298 public String
toString() {
299 return GitBundle
.message("push.active.commit.node", revision
.asString().substring(0, HASH_PREFIX_SIZE
), message
);
308 * if true, the update is required
312 * the path to vcs root
324 * the remote branch name
330 List
<Commit
> commits
= new ArrayList
<Commit
>();
336 public String
toString() {
337 if (branch
== null) {
338 return GitBundle
.message("push.active.root.node.no.branch", root
.getPresentableUrl());
340 if (remote
== null) {
341 return GitBundle
.message("push.active.root.node.no.tracked", root
.getPresentableUrl(), branch
);
343 if (commits
.size() == 0) {
344 return GitBundle
.message("push.active.root.node.no.commits", root
.getPresentableUrl(), branch
, remote
, remoteBranch
);
346 if (remoteCommits
!= 0) {
347 return GitBundle
.message("push.active.root.node.behind", root
.getPresentableUrl(), branch
, remote
, remoteBranch
);
349 return GitBundle
.message("push.active.root.node.push", root
.getPresentableUrl(), branch
, remote
, remoteBranch
);