1
/*******************************************************************************
2 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
3 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
7 * All rights reserved. This program and the accompanying materials
8 * are made available under the terms of the Eclipse Public License v1.0
9 * which accompanies this distribution, and is available at
10 * http://www.eclipse.org/legal/epl-v10.html
11 *******************************************************************************/
12 package org
.eclipse
.egit
.ui
.internal
.dialogs
;
14 import java
.io
.IOException
;
15 import java
.util
.ArrayList
;
16 import java
.util
.List
;
18 import org
.eclipse
.egit
.ui
.Activator
;
19 import org
.eclipse
.egit
.ui
.UIText
;
20 import org
.eclipse
.egit
.ui
.internal
.ValidationUtils
;
21 import org
.eclipse
.egit
.ui
.internal
.repository
.RepositoriesViewContentProvider
;
22 import org
.eclipse
.egit
.ui
.internal
.repository
.RepositoriesViewLabelProvider
;
23 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.LocalBranchesNode
;
24 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.RefNode
;
25 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.RemoteBranchesNode
;
26 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.RepositoryTreeNode
;
27 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.RepositoryTreeNodeType
;
28 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.TagNode
;
29 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.TagsNode
;
30 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
31 import org
.eclipse
.jface
.dialogs
.InputDialog
;
32 import org
.eclipse
.jface
.dialogs
.TitleAreaDialog
;
33 import org
.eclipse
.jface
.layout
.GridDataFactory
;
34 import org
.eclipse
.jface
.layout
.GridLayoutFactory
;
35 import org
.eclipse
.jface
.resource
.JFaceResources
;
36 import org
.eclipse
.jface
.viewers
.IOpenListener
;
37 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
38 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
39 import org
.eclipse
.jface
.viewers
.OpenEvent
;
40 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
41 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
42 import org
.eclipse
.jface
.viewers
.TreeViewer
;
43 import org
.eclipse
.jface
.window
.Window
;
44 import org
.eclipse
.jgit
.lib
.Constants
;
45 import org
.eclipse
.jgit
.lib
.ObjectId
;
46 import org
.eclipse
.jgit
.lib
.Ref
;
47 import org
.eclipse
.jgit
.lib
.RefRename
;
48 import org
.eclipse
.jgit
.lib
.RefUpdate
;
49 import org
.eclipse
.jgit
.lib
.Repository
;
50 import org
.eclipse
.jgit
.lib
.RefUpdate
.Result
;
51 import org
.eclipse
.osgi
.util
.NLS
;
52 import org
.eclipse
.swt
.SWT
;
53 import org
.eclipse
.swt
.events
.SelectionAdapter
;
54 import org
.eclipse
.swt
.events
.SelectionEvent
;
55 import org
.eclipse
.swt
.layout
.GridLayout
;
56 import org
.eclipse
.swt
.widgets
.Button
;
57 import org
.eclipse
.swt
.widgets
.Composite
;
58 import org
.eclipse
.swt
.widgets
.Shell
;
59 import org
.eclipse
.ui
.dialogs
.FilteredTree
;
60 import org
.eclipse
.ui
.dialogs
.PatternFilter
;
63 * The branch and reset selection dialog
65 public class BranchSelectionDialog
extends TitleAreaDialog
{
67 private final Repository repo
;
69 private TreeViewer branchTree
;
72 * button which finally triggers the action
74 protected Button confirmationBtn
;
76 private Button renameButton
;
78 private Button newButton
;
80 private String selectedBranch
;
82 private final RepositoryTreeNode
<Repository
> localBranches
;
84 private final RepositoryTreeNode
<Repository
> remoteBranches
;
86 private final RepositoryTreeNode
<Repository
> tags
;
89 * Construct a dialog to select a branch to reset to or check out
93 public BranchSelectionDialog(Shell parentShell
, Repository repo
) {
96 localBranches
= new LocalBranchesNode(null, this.repo
);
97 remoteBranches
= new RemoteBranchesNode(null, this.repo
);
98 tags
= new TagsNode(null, this.repo
);
102 protected Composite
createDialogArea(Composite base
) {
103 Composite parent
= (Composite
) super.createDialogArea(base
);
104 parent
.setLayout(GridLayoutFactory
.fillDefaults().create());
106 // TODO deprecated constructor for now
107 FilteredTree tree
= new FilteredTree(parent
, SWT
.SINGLE
| SWT
.BORDER
, new PatternFilter());
108 branchTree
= tree
.getViewer();
109 new RepositoriesViewLabelProvider(branchTree
);
110 branchTree
.setContentProvider(new RepositoriesViewContentProvider());
112 GridDataFactory
.fillDefaults().grab(true, true).hint(500, 300).applyTo(
114 branchTree
.addSelectionChangedListener(new ISelectionChangedListener() {
116 public void selectionChanged(SelectionChangedEvent event
) {
117 // enable the buttons depending on the selection
119 String refName
= refNameFromDialog();
121 boolean tagSelected
= refName
!= null
122 && refName
.startsWith(Constants
.R_TAGS
);
124 boolean branchSelected
= refName
!= null
125 && (refName
.startsWith(Constants
.R_HEADS
) || refName
126 .startsWith(Constants
.R_REMOTES
));
128 // we don't allow reset on tags, but checkout
129 if (!canConfirmOnTag())
130 confirmationBtn
.setEnabled(branchSelected
);
132 confirmationBtn
.setEnabled(branchSelected
|| tagSelected
);
134 // we don't support rename on tags
135 if (renameButton
!= null) {
136 renameButton
.setEnabled(branchSelected
&& !tagSelected
140 // new branch can not be based on a tag
141 if (newButton
!= null) {
142 newButton
.setEnabled(branchSelected
&& !tagSelected
);
147 // double-click support
148 branchTree
.addOpenListener(new IOpenListener() {
150 public void open(OpenEvent event
) {
151 RepositoryTreeNode node
= (RepositoryTreeNode
) ((IStructuredSelection
) branchTree
152 .getSelection()).getFirstElement();
153 if (node
.getType() != RepositoryTreeNodeType
.REF
154 && node
.getType() != RepositoryTreeNodeType
.TAG
)
155 branchTree
.setExpandedState(node
, !branchTree
156 .getExpandedState(node
));
157 else if (confirmationBtn
.isEnabled())
163 createCustomArea(parent
);
165 String rawTitle
= getTitle();
166 String title
= NLS
.bind(rawTitle
, new Object
[] { repo
.getDirectory() });
169 setMessage(getMessageText());
170 getShell().setText(title
);
176 public void create() {
179 List
<RepositoryTreeNode
> roots
= new ArrayList
<RepositoryTreeNode
>();
180 roots
.add(localBranches
);
181 roots
.add(remoteBranches
);
184 branchTree
.setInput(roots
);
187 // initially, we mark the current head if it can be determined
188 String fullBranch
= repo
.getFullBranch();
189 if (!markRef(fullBranch
))
190 // if we can't determine a branch, we just expand local branches
191 branchTree
.expandToLevel(localBranches
, 1);
192 } catch (IOException e
) {
197 private boolean markRef(String refName
) {
198 // selects the entry specified by the name
202 RepositoryTreeNode node
;
204 if (refName
.startsWith(Constants
.R_HEADS
)) {
205 Ref ref
= this.repo
.getRef(refName
);
206 node
= new RefNode(localBranches
, this.repo
, ref
);
208 String mappedRef
= Activator
.getDefault().getRepositoryUtil()
209 .mapCommitToRef(this.repo
, refName
, false);
210 if (mappedRef
!= null
211 && mappedRef
.startsWith(Constants
.R_REMOTES
)) {
212 Ref ref
= this.repo
.getRef(mappedRef
);
213 node
= new RefNode(remoteBranches
, this.repo
, ref
);
214 } else if (mappedRef
!= null
215 && mappedRef
.startsWith(Constants
.R_TAGS
)) {
216 Ref ref
= this.repo
.getRef(mappedRef
);
217 node
= new TagNode(tags
, this.repo
, ref
);
222 } catch (IOException e
) {
226 branchTree
.setSelection(new StructuredSelection(node
), true);
231 * @return the selected refName
233 public String
getRefName() {
234 return this.selectedBranch
;
238 protected void okPressed() {
239 this.selectedBranch
= refNameFromDialog();
243 private String
refNameFromDialog() {
244 IStructuredSelection sel
= (IStructuredSelection
) branchTree
248 RepositoryTreeNode node
= (RepositoryTreeNode
) sel
.getFirstElement();
249 if (node
.getType() == RepositoryTreeNodeType
.REF
250 || node
.getType() == RepositoryTreeNodeType
.TAG
) {
251 return ((Ref
) node
.getObject()).getName();
256 private InputDialog
getRefNameInputDialog(String prompt
, final String refPrefix
) {
257 InputDialog labelDialog
= new InputDialog(
259 UIText
.BranchSelectionDialog_QuestionNewBranchTitle
,
261 null, ValidationUtils
.getRefNameInputValidator(repo
, refPrefix
));
262 labelDialog
.setBlockOnOpen(true);
267 protected void createButtonsForButtonBar(Composite parent
) {
268 newButton
= new Button(parent
, SWT
.PUSH
);
269 newButton
.setFont(JFaceResources
.getDialogFont());
270 newButton
.setText(UIText
.BranchSelectionDialog_NewBranch
);
271 setButtonLayoutData(newButton
);
272 ((GridLayout
)parent
.getLayout()).numColumns
++;
274 renameButton
= new Button(parent
, SWT
.PUSH
);
275 renameButton
.setFont(JFaceResources
.getDialogFont());
276 renameButton
.setText(UIText
.BranchSelectionDialog_Rename
);
277 setButtonLayoutData(renameButton
);
278 ((GridLayout
)parent
.getLayout()).numColumns
++;
280 renameButton
.addSelectionListener(new SelectionAdapter() {
281 public void widgetSelected(SelectionEvent e
) {
283 String refName
= refNameFromDialog();
286 // the button should be disabled anyway, but we check again
287 if (refName
.equals(Constants
.HEAD
))
290 if (refName
.startsWith(Constants
.R_HEADS
))
291 refPrefix
= Constants
.R_HEADS
;
292 else if (refName
.startsWith(Constants
.R_REMOTES
))
293 refPrefix
= Constants
.R_REMOTES
;
294 else if (refName
.startsWith(Constants
.R_TAGS
))
295 refPrefix
= Constants
.R_TAGS
;
297 // the button should be disabled anyway, but we check again
301 String branchName
= refName
.substring(refPrefix
.length());
303 InputDialog labelDialog
= getRefNameInputDialog(NLS
305 UIText
.BranchSelectionDialog_QuestionNewBranchNameMessage
,
306 branchName
, refPrefix
), refPrefix
);
307 if (labelDialog
.open() == Window
.OK
) {
308 String newRefName
= refPrefix
+ labelDialog
.getValue();
310 RefRename renameRef
= repo
.renameRef(refName
, newRefName
);
311 if (renameRef
.rename() != Result
.RENAMED
) {
314 UIText
.BranchSelectionDialog_ErrorCouldNotRenameRef
,
315 refName
, newRefName
, renameRef
318 branchTree
.refresh();
320 } catch (Throwable e1
) {
323 UIText
.BranchSelectionDialog_ErrorCouldNotRenameRef
,
324 refName
, newRefName
, e1
.getMessage());
329 newButton
.addSelectionListener(new SelectionAdapter() {
331 public void widgetSelected(SelectionEvent e
) {
332 // check what ref name the user selected, if any.
333 String refName
= refNameFromDialog();
335 // the button should be disabled anyway, but we check again
336 if (refName
.equals(Constants
.HEAD
))
338 if (refName
.startsWith(Constants
.R_TAGS
))
339 // the button should be disabled anyway, but we check again
342 InputDialog labelDialog
= getRefNameInputDialog(
345 UIText
.BranchSelectionDialog_QuestionNewBranchMessage
,
346 refName
, Constants
.R_HEADS
),
349 if (labelDialog
.open() == Window
.OK
) {
350 String newRefName
= Constants
.R_HEADS
+ labelDialog
.getValue();
353 updateRef
= repo
.updateRef(newRefName
);
354 Ref startRef
= repo
.getRef(refName
);
355 ObjectId startAt
= repo
.resolve(refName
);
357 if (startRef
!= null)
358 startBranch
= refName
;
360 startBranch
= startAt
.name();
361 startBranch
= repo
.shortenRefName(startBranch
);
362 updateRef
.setNewObjectId(startAt
);
363 updateRef
.setRefLogMessage("branch: Created from " + startBranch
, false); //$NON-NLS-1$
365 branchTree
.refresh();
367 } catch (Throwable e1
) {
370 UIText
.BranchSelectionDialog_ErrorCouldNotCreateNewRef
,
376 confirmationBtn
= createButton(parent
, IDialogConstants
.OK_ID
,
377 UIText
.BranchSelectionDialog_OkCheckout
, true);
378 createButton(parent
, IDialogConstants
.CANCEL_ID
, IDialogConstants
.CANCEL_LABEL
, false);
380 // can't advance without a selection
381 confirmationBtn
.setEnabled(!branchTree
.getSelection().isEmpty());
385 * @return the message shown above the refs tree
387 protected String
getMessageText() {
388 return UIText
.BranchSelectionDialog_Refs
;
392 * Subclasses may add UI elements
395 protected void createCustomArea(Composite parent
) {
400 * Subclasses may change the title of the dialog
401 * @return the title of the dialog
403 protected String
getTitle() {
404 return UIText
.BranchSelectionDialog_TitleCheckout
;
409 * @return if the confirmation button is enabled when a tag is selected
411 protected boolean canConfirmOnTag() {
416 protected int getShellStyle() {
417 return super.getShellStyle() | SWT
.RESIZE
;
420 private void reportError(Throwable e
, String message
, Object
... args
) {
421 String msg
= NLS
.bind(message
, args
);
422 Activator
.handleError(msg
, e
, true);