Initial EGit contribution to eclipse.org
[egit.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / dialogs / BranchSelectionDialog.java
blobefe42134c2d345bb165f33a7ee5ac44969eaebc8
1 /*******************************************************************************
2 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
3 * Copyright (C) 2007, Robin Rosenberg <me@lathund.dewire.com.dewire.com>
4 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
5 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
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.Collections;
17 import java.util.List;
19 import org.eclipse.egit.core.op.ResetOperation.ResetType;
20 import org.eclipse.egit.ui.Activator;
21 import org.eclipse.egit.ui.UIText;
22 import org.eclipse.jface.dialogs.Dialog;
23 import org.eclipse.jface.dialogs.IDialogConstants;
24 import org.eclipse.jface.dialogs.IInputValidator;
25 import org.eclipse.jface.dialogs.InputDialog;
26 import org.eclipse.jface.dialogs.MessageDialog;
27 import org.eclipse.jface.layout.GridDataFactory;
28 import org.eclipse.jface.layout.GridLayoutFactory;
29 import org.eclipse.jface.resource.JFaceResources;
30 import org.eclipse.jface.window.Window;
31 import org.eclipse.osgi.util.NLS;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.DisposeEvent;
34 import org.eclipse.swt.events.DisposeListener;
35 import org.eclipse.swt.events.SelectionEvent;
36 import org.eclipse.swt.events.SelectionListener;
37 import org.eclipse.swt.graphics.Font;
38 import org.eclipse.swt.graphics.FontData;
39 import org.eclipse.swt.layout.GridLayout;
40 import org.eclipse.swt.layout.RowLayout;
41 import org.eclipse.swt.widgets.Button;
42 import org.eclipse.swt.widgets.Composite;
43 import org.eclipse.swt.widgets.Event;
44 import org.eclipse.swt.widgets.Group;
45 import org.eclipse.swt.widgets.Label;
46 import org.eclipse.swt.widgets.Listener;
47 import org.eclipse.swt.widgets.Shell;
48 import org.eclipse.swt.widgets.Tree;
49 import org.eclipse.swt.widgets.TreeItem;
50 import org.eclipse.jgit.lib.Constants;
51 import org.eclipse.jgit.lib.ObjectId;
52 import org.eclipse.jgit.lib.Ref;
53 import org.eclipse.jgit.lib.RefRename;
54 import org.eclipse.jgit.lib.RefUpdate;
55 import org.eclipse.jgit.lib.Repository;
56 import org.eclipse.jgit.lib.RefUpdate.Result;
58 /**
59 * The branch and reset selection dialog
62 public class BranchSelectionDialog extends Dialog {
63 private final Repository repo;
65 private boolean showResetType = true;
67 /**
68 * Construct a dialog to select a branch to reset to or check out
69 * @param parentShell
70 * @param repo
72 public BranchSelectionDialog(Shell parentShell, Repository repo) {
73 super(parentShell);
74 this.repo = repo;
77 /**
78 * Pre-set whether or present a reset or checkout dialog
79 * @param show
81 public void setShowResetType(boolean show) {
82 this.showResetType = show;
85 private Composite parent;
87 private Tree branchTree;
89 @Override
90 protected Composite createDialogArea(Composite base) {
91 parent = (Composite) super.createDialogArea(base);
92 parent.setLayout(GridLayoutFactory.swtDefaults().create());
93 new Label(parent, SWT.NONE).setText(UIText.BranchSelectionDialog_Refs);
94 branchTree = new Tree(parent, SWT.BORDER);
95 branchTree.setLayoutData(GridDataFactory.fillDefaults().grab(true,true).hint(500, 300).create());
97 if (showResetType) {
98 buildResetGroup();
101 String rawTitle = showResetType ? UIText.BranchSelectionDialog_TitleReset
102 : UIText.BranchSelectionDialog_TitleCheckout;
103 getShell().setText(
104 NLS.bind(rawTitle, new Object[] { repo.getDirectory() }));
106 try {
107 fillTreeWithBranches(null);
108 } catch (Throwable e) {
109 Activator.logError(UIText.BranchSelectionDialog_ErrorCouldNotRefresh, e);
112 return parent;
115 private void buildResetGroup() {
116 Group g = new Group(parent, SWT.NONE);
117 g.setText(UIText.BranchSelectionDialog_ResetType);
118 g.setLayoutData(GridDataFactory.swtDefaults().align(SWT.CENTER, SWT.CENTER).create());
119 g.setLayout(new RowLayout(SWT.VERTICAL));
121 Button soft = new Button(g, SWT.RADIO);
122 soft.setText(UIText.BranchSelectionDialog_ResetTypeSoft);
123 soft.addListener(SWT.Selection, new Listener() {
124 public void handleEvent(Event event) {
125 resetType = ResetType.SOFT;
129 Button medium = new Button(g, SWT.RADIO);
130 medium.setSelection(true);
131 medium.setText(UIText.BranchSelectionDialog_ResetTypeMixed);
132 medium.addListener(SWT.Selection, new Listener() {
133 public void handleEvent(Event event) {
134 resetType = ResetType.MIXED;
138 Button hard = new Button(g, SWT.RADIO);
139 hard.setText(UIText.BranchSelectionDialog_ResetTypeHard);
140 hard.addListener(SWT.Selection, new Listener() {
141 public void handleEvent(Event event) {
142 resetType = ResetType.HARD;
147 private void fillTreeWithBranches(String select) throws IOException {
148 String branch = repo.getFullBranch();
149 List<String> branches = new ArrayList<String>(repo.getAllRefs()
150 .keySet());
151 Collections.sort(branches);
153 TreeItem curItem = null;
154 TreeItem curSubItem = null;
155 String curPrefix = null;
156 String curSubPrefix = null;
157 TreeItem itemToSelect = null;
159 for (String ref : branches) {
160 String shortName = ref;
161 if (ref.startsWith(Constants.R_HEADS)) {
162 shortName = ref.substring(11);
163 if (!Constants.R_HEADS.equals(curPrefix)) {
164 curPrefix = Constants.R_HEADS;
165 curSubPrefix = null;
166 curSubItem = null;
167 curItem = new TreeItem(branchTree, SWT.NONE);
168 curItem.setText(UIText.BranchSelectionDialog_LocalBranches);
170 } else if (ref.startsWith(Constants.R_REMOTES)) {
171 shortName = ref.substring(13);
172 if (!Constants.R_REMOTES.equals(curPrefix)) {
173 curPrefix = Constants.R_REMOTES;
174 curItem = new TreeItem(branchTree, SWT.NONE);
175 curItem.setText(UIText.BranchSelectionDialog_RemoteBranches);
176 curSubItem = null;
177 curSubPrefix = null;
180 int slashPos = shortName.indexOf("/"); //$NON-NLS-1$
181 if (slashPos > -1) {
182 String remoteName = shortName.substring(0, slashPos);
183 shortName = shortName.substring(slashPos+1);
184 if (!remoteName.equals(curSubPrefix)) {
185 curSubItem = new TreeItem(curItem, SWT.NONE);
186 curSubItem.setText(remoteName);
187 curSubPrefix = remoteName;
189 } else {
190 curSubItem = null;
191 curSubPrefix = null;
193 } else if (ref.startsWith(Constants.R_TAGS)) {
194 shortName = ref.substring(10);
195 if (!Constants.R_TAGS.equals(curPrefix)) {
196 curPrefix = Constants.R_TAGS;
197 curSubPrefix = null;
198 curSubItem = null;
199 curItem = new TreeItem(branchTree, SWT.NONE);
200 curItem.setText(UIText.BranchSelectionDialog_Tags);
203 TreeItem item;
204 if (curItem == null)
205 item = new TreeItem(branchTree, SWT.NONE);
206 else if (curSubItem == null)
207 item = new TreeItem(curItem, SWT.NONE);
208 else item = new TreeItem(curSubItem, SWT.NONE);
209 item.setData(ref);
210 if (ref.equals(branch)) {
211 item.setText(shortName + UIText.BranchSelectionDialog_BranchSuffix_Current);
212 FontData fd = item.getFont().getFontData()[0];
213 fd.setStyle(fd.getStyle() | SWT.BOLD);
214 final Font f = new Font(getShell().getDisplay(), fd);
215 item.setFont(f);
216 item.addDisposeListener(new DisposeListener() {
217 public void widgetDisposed(DisposeEvent e) {
218 f.dispose();
221 branchTree.showItem(item);
223 else item.setText(shortName);
224 if (ref.equals(select))
225 itemToSelect = item;
226 branchTree.setLinesVisible(true);
228 if (itemToSelect != null) {
229 branchTree.select(itemToSelect);
230 branchTree.showItem(itemToSelect);
234 private String refName = null;
237 * @return Selected ref
239 public String getRefName() {
240 return refName;
243 private ResetType resetType = ResetType.MIXED;
246 * @return Type of Reset
248 public ResetType getResetType() {
249 return resetType;
252 @Override
253 protected void okPressed() {
254 refNameFromDialog();
255 if (refName == null) {
256 MessageDialog.openWarning(getShell(),
257 UIText.BranchSelectionDialog_NoBranchSeletectTitle,
258 UIText.BranchSelectionDialog_NoBranchSeletectMessage);
259 return;
262 if (showResetType) {
263 if (resetType == ResetType.HARD) {
264 if (!MessageDialog.openQuestion(getShell(),
265 UIText.BranchSelectionDialog_ReallyResetTitle,
266 UIText.BranchSelectionDialog_ReallyResetMessage)) {
267 return;
272 super.okPressed();
275 private void refNameFromDialog() {
276 TreeItem[] selection = branchTree.getSelection();
277 refName = null;
278 if (selection != null && selection.length > 0) {
279 TreeItem item = selection[0];
280 refName = (String) item.getData();
284 private InputDialog getRefNameInputDialog(String prompt) {
285 InputDialog labelDialog = new InputDialog(
286 getShell(),
287 UIText.BranchSelectionDialog_QuestionNewBranchTitle,
288 prompt,
289 null, new IInputValidator() {
290 public String isValid(String newText) {
291 String testFor = Constants.R_HEADS + newText;
292 try {
293 if (repo.resolve(testFor) != null)
294 return UIText.BranchSelectionDialog_ErrorAlreadyExists;
295 } catch (IOException e1) {
296 Activator.logError(NLS.bind(
297 UIText.BranchSelectionDialog_ErrorCouldNotResolve, testFor), e1);
298 return e1.getMessage();
300 if (!Repository.isValidRefName(testFor))
301 return UIText.BranchSelectionDialog_ErrorInvalidRefName;
302 return null;
305 labelDialog.setBlockOnOpen(true);
306 return labelDialog;
309 @Override
310 protected void createButtonsForButtonBar(Composite parent) {
311 if (!showResetType) {
312 Button newButton = new Button(parent, SWT.PUSH);
313 newButton.setFont(JFaceResources.getDialogFont());
314 newButton.setText(UIText.BranchSelectionDialog_NewBranch);
315 ((GridLayout)parent.getLayout()).numColumns++;
316 Button renameButton = new Button(parent, SWT.PUSH);
317 renameButton.setText(UIText.BranchSelectionDialog_Rename);
318 renameButton.addSelectionListener(new SelectionListener() {
319 public void widgetSelected(SelectionEvent e) {
320 // check what ref name the user selected, if any.
321 refNameFromDialog();
323 String branchName;
324 if (refName.startsWith(Constants.R_HEADS))
325 branchName = refName.substring(Constants.R_HEADS.length());
326 else
327 branchName = refName;
328 InputDialog labelDialog = getRefNameInputDialog(NLS
329 .bind(
330 UIText.BranchSelectionDialog_QuestionNewBranchNameMessage,
331 branchName));
332 if (labelDialog.open() == Window.OK) {
333 String newRefName = Constants.R_HEADS + labelDialog.getValue();
334 try {
335 RefRename renameRef = repo.renameRef(refName, newRefName);
336 if (renameRef.rename() != Result.RENAMED) {
337 reportError(
338 null,
339 UIText.BranchSelectionDialog_BranchSelectionDialog_RenamedFailedTitle,
340 UIText.BranchSelectionDialog_ErrorCouldNotRenameRef,
341 refName, newRefName, renameRef
342 .getResult());
344 } catch (Throwable e1) {
345 reportError(
347 UIText.BranchSelectionDialog_BranchSelectionDialog_RenamedFailedTitle,
348 UIText.BranchSelectionDialog_ErrorCouldNotRenameRef,
349 refName, newRefName, e1.getMessage());
351 try {
352 branchTree.removeAll();
353 fillTreeWithBranches(newRefName);
354 } catch (Throwable e1) {
355 reportError(
357 UIText.BranchSelectionDialog_BranchSelectionDialog_RenamedFailedTitle,
358 UIText.BranchSelectionDialog_ErrorCouldNotRefreshBranchList);
362 public void widgetDefaultSelected(SelectionEvent e) {
363 widgetSelected(e);
366 newButton.addSelectionListener(new SelectionListener() {
368 public void widgetSelected(SelectionEvent e) {
369 // check what ref name the user selected, if any.
370 refNameFromDialog();
372 InputDialog labelDialog = getRefNameInputDialog(UIText.BranchSelectionDialog_QuestionNewBranchNameMessage);
373 if (labelDialog.open() == Window.OK) {
374 String newRefName = Constants.R_HEADS + labelDialog.getValue();
375 RefUpdate updateRef;
376 try {
377 updateRef = repo.updateRef(newRefName);
378 Ref startRef = repo.getRef(refName);
379 ObjectId startAt;
380 if (refName == null)
381 startAt = repo.resolve(Constants.HEAD);
382 else
383 startAt = repo.resolve(refName);
384 String startBranch;
385 if (startRef != null)
386 startBranch = refName;
387 else
388 startBranch = startAt.name();
389 startBranch = repo.shortenRefName(startBranch);
390 updateRef.setNewObjectId(startAt);
391 updateRef.setRefLogMessage("branch: Created from " + startBranch, false); //$NON-NLS-1$
392 updateRef.update();
393 } catch (Throwable e1) {
394 reportError(
396 UIText.BranchSelectionDialog_BranchSelectionDialog_CreateFailedTitle,
397 UIText.BranchSelectionDialog_ErrorCouldNotCreateNewRef,
398 newRefName);
400 try {
401 branchTree.removeAll();
402 fillTreeWithBranches(newRefName);
403 } catch (Throwable e1) {
404 reportError(e1,
405 UIText.BranchSelectionDialog_BranchSelectionDialog_CreateFailedTitle,
406 UIText.BranchSelectionDialog_ErrorCouldNotRefreshBranchList);
412 public void widgetDefaultSelected(SelectionEvent e) {
413 widgetSelected(e);
417 createButton(parent, IDialogConstants.OK_ID,
418 showResetType ? UIText.BranchSelectionDialog_OkReset
419 : UIText.BranchSelectionDialog_OkCheckout, true);
420 createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
423 @Override
424 protected int getShellStyle() {
425 return super.getShellStyle() | SWT.RESIZE;
428 private void reportError(Throwable e, String title, String message,
429 Object... args) {
430 String msg = NLS.bind(message, args);
431 MessageDialog.openError(getShell(), title, msg);
432 Activator.logError(msg, e);