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
);
172 applyDialogFont(parent
);
178 public void create() {
181 List
<RepositoryTreeNode
> roots
= new ArrayList
<RepositoryTreeNode
>();
182 roots
.add(localBranches
);
183 roots
.add(remoteBranches
);
186 branchTree
.setInput(roots
);
189 // initially, we mark the current head if it can be determined
190 String fullBranch
= repo
.getFullBranch();
191 if (!markRef(fullBranch
))
192 // if we can't determine a branch, we just expand local branches
193 branchTree
.expandToLevel(localBranches
, 1);
194 } catch (IOException e
) {
199 private boolean markRef(String refName
) {
200 // selects the entry specified by the name
204 RepositoryTreeNode node
;
206 if (refName
.startsWith(Constants
.R_HEADS
)) {
207 Ref ref
= this.repo
.getRef(refName
);
208 node
= new RefNode(localBranches
, this.repo
, ref
);
210 String mappedRef
= Activator
.getDefault().getRepositoryUtil()
211 .mapCommitToRef(this.repo
, refName
, false);
212 if (mappedRef
!= null
213 && mappedRef
.startsWith(Constants
.R_REMOTES
)) {
214 Ref ref
= this.repo
.getRef(mappedRef
);
215 node
= new RefNode(remoteBranches
, this.repo
, ref
);
216 } else if (mappedRef
!= null
217 && mappedRef
.startsWith(Constants
.R_TAGS
)) {
218 Ref ref
= this.repo
.getRef(mappedRef
);
219 node
= new TagNode(tags
, this.repo
, ref
);
224 } catch (IOException e
) {
228 branchTree
.setSelection(new StructuredSelection(node
), true);
233 * @return the selected refName
235 public String
getRefName() {
236 return this.selectedBranch
;
240 protected void okPressed() {
241 this.selectedBranch
= refNameFromDialog();
245 private String
refNameFromDialog() {
246 IStructuredSelection sel
= (IStructuredSelection
) branchTree
250 RepositoryTreeNode node
= (RepositoryTreeNode
) sel
.getFirstElement();
251 if (node
.getType() == RepositoryTreeNodeType
.REF
252 || node
.getType() == RepositoryTreeNodeType
.TAG
) {
253 return ((Ref
) node
.getObject()).getName();
258 private InputDialog
getRefNameInputDialog(String prompt
, final String refPrefix
) {
259 InputDialog labelDialog
= new InputDialog(
261 UIText
.BranchSelectionDialog_QuestionNewBranchTitle
,
263 null, ValidationUtils
.getRefNameInputValidator(repo
, refPrefix
));
264 labelDialog
.setBlockOnOpen(true);
269 protected void createButtonsForButtonBar(Composite parent
) {
270 newButton
= new Button(parent
, SWT
.PUSH
);
271 newButton
.setFont(JFaceResources
.getDialogFont());
272 newButton
.setText(UIText
.BranchSelectionDialog_NewBranch
);
273 setButtonLayoutData(newButton
);
274 ((GridLayout
)parent
.getLayout()).numColumns
++;
276 renameButton
= new Button(parent
, SWT
.PUSH
);
277 renameButton
.setFont(JFaceResources
.getDialogFont());
278 renameButton
.setText(UIText
.BranchSelectionDialog_Rename
);
279 setButtonLayoutData(renameButton
);
280 ((GridLayout
)parent
.getLayout()).numColumns
++;
282 renameButton
.addSelectionListener(new SelectionAdapter() {
283 public void widgetSelected(SelectionEvent e
) {
285 String refName
= refNameFromDialog();
288 // the button should be disabled anyway, but we check again
289 if (refName
.equals(Constants
.HEAD
))
292 if (refName
.startsWith(Constants
.R_HEADS
))
293 refPrefix
= Constants
.R_HEADS
;
294 else if (refName
.startsWith(Constants
.R_REMOTES
))
295 refPrefix
= Constants
.R_REMOTES
;
296 else if (refName
.startsWith(Constants
.R_TAGS
))
297 refPrefix
= Constants
.R_TAGS
;
299 // the button should be disabled anyway, but we check again
303 String branchName
= refName
.substring(refPrefix
.length());
305 InputDialog labelDialog
= getRefNameInputDialog(NLS
307 UIText
.BranchSelectionDialog_QuestionNewBranchNameMessage
,
308 branchName
, refPrefix
), refPrefix
);
309 if (labelDialog
.open() == Window
.OK
) {
310 String newRefName
= refPrefix
+ labelDialog
.getValue();
312 RefRename renameRef
= repo
.renameRef(refName
, newRefName
);
313 if (renameRef
.rename() != Result
.RENAMED
) {
316 UIText
.BranchSelectionDialog_ErrorCouldNotRenameRef
,
317 refName
, newRefName
, renameRef
320 branchTree
.refresh();
322 } catch (Throwable e1
) {
325 UIText
.BranchSelectionDialog_ErrorCouldNotRenameRef
,
326 refName
, newRefName
, e1
.getMessage());
331 newButton
.addSelectionListener(new SelectionAdapter() {
333 public void widgetSelected(SelectionEvent e
) {
334 // check what ref name the user selected, if any.
335 String refName
= refNameFromDialog();
337 // the button should be disabled anyway, but we check again
338 if (refName
.equals(Constants
.HEAD
))
340 if (refName
.startsWith(Constants
.R_TAGS
))
341 // the button should be disabled anyway, but we check again
344 InputDialog labelDialog
= getRefNameInputDialog(
347 UIText
.BranchSelectionDialog_QuestionNewBranchMessage
,
348 refName
, Constants
.R_HEADS
),
351 if (labelDialog
.open() == Window
.OK
) {
352 String newRefName
= Constants
.R_HEADS
+ labelDialog
.getValue();
355 updateRef
= repo
.updateRef(newRefName
);
356 Ref startRef
= repo
.getRef(refName
);
357 ObjectId startAt
= repo
.resolve(refName
);
359 if (startRef
!= null)
360 startBranch
= refName
;
362 startBranch
= startAt
.name();
363 startBranch
= repo
.shortenRefName(startBranch
);
364 updateRef
.setNewObjectId(startAt
);
365 updateRef
.setRefLogMessage("branch: Created from " + startBranch
, false); //$NON-NLS-1$
367 branchTree
.refresh();
369 } catch (Throwable e1
) {
372 UIText
.BranchSelectionDialog_ErrorCouldNotCreateNewRef
,
378 confirmationBtn
= createButton(parent
, IDialogConstants
.OK_ID
,
379 UIText
.BranchSelectionDialog_OkCheckout
, true);
380 createButton(parent
, IDialogConstants
.CANCEL_ID
, IDialogConstants
.CANCEL_LABEL
, false);
382 // can't advance without a selection
383 confirmationBtn
.setEnabled(!branchTree
.getSelection().isEmpty());
387 * @return the message shown above the refs tree
389 protected String
getMessageText() {
390 return UIText
.BranchSelectionDialog_Refs
;
394 * Subclasses may add UI elements
397 protected void createCustomArea(Composite parent
) {
402 * Subclasses may change the title of the dialog
403 * @return the title of the dialog
405 protected String
getTitle() {
406 return UIText
.BranchSelectionDialog_TitleCheckout
;
411 * @return if the confirmation button is enabled when a tag is selected
413 protected boolean canConfirmOnTag() {
418 protected int getShellStyle() {
419 return super.getShellStyle() | SWT
.RESIZE
;
422 private void reportError(Throwable e
, String message
, Object
... args
) {
423 String msg
= NLS
.bind(message
, args
);
424 Activator
.handleError(msg
, e
, true);