Git Import Wizard
[egit.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / clone / CloneDestinationPage.java
blobc9f16546eed677fa5fd292e14adc234bb1e9b2f1
1 /*******************************************************************************
2 * Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
5 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.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.clone;
14 import java.io.File;
15 import java.util.List;
17 import org.eclipse.core.resources.ResourcesPlugin;
18 import org.eclipse.egit.ui.UIText;
19 import org.eclipse.egit.ui.internal.components.RepositorySelection;
20 import org.eclipse.egit.ui.internal.components.RepositorySelectionPage;
21 import org.eclipse.egit.ui.internal.components.SelectionChangeListener;
22 import org.eclipse.jface.wizard.WizardPage;
23 import org.eclipse.jgit.lib.Constants;
24 import org.eclipse.jgit.lib.Ref;
25 import org.eclipse.osgi.util.NLS;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.events.ModifyEvent;
28 import org.eclipse.swt.events.ModifyListener;
29 import org.eclipse.swt.events.SelectionAdapter;
30 import org.eclipse.swt.events.SelectionEvent;
31 import org.eclipse.swt.layout.GridData;
32 import org.eclipse.swt.layout.GridLayout;
33 import org.eclipse.swt.widgets.Button;
34 import org.eclipse.swt.widgets.Combo;
35 import org.eclipse.swt.widgets.Composite;
36 import org.eclipse.swt.widgets.FileDialog;
37 import org.eclipse.swt.widgets.Group;
38 import org.eclipse.swt.widgets.Label;
39 import org.eclipse.swt.widgets.Text;
41 /**
42 * Wizard page that allows the user entering the location of a repository to be
43 * cloned.
45 class CloneDestinationPage extends WizardPage {
46 private final RepositorySelectionPage sourcePage;
48 private final SourceBranchPage branchPage;
50 private RepositorySelection validatedRepoSelection;
52 private List<Ref> validatedSelectedBranches;
54 private Ref validatedHEAD;
56 private Combo initialBranch;
58 private Text directoryText;
60 private Text remoteText;
62 CloneDestinationPage(final RepositorySelectionPage sp,
63 final SourceBranchPage bp) {
64 super(CloneDestinationPage.class.getName());
65 sourcePage = sp;
66 branchPage = bp;
67 setTitle(UIText.CloneDestinationPage_title);
69 final SelectionChangeListener listener = new SelectionChangeListener() {
70 public void selectionChanged() {
71 checkPreviousPagesSelections();
74 sourcePage.addSelectionListener(listener);
75 branchPage.addSelectionListener(listener);
78 public void createControl(final Composite parent) {
79 final Composite panel = new Composite(parent, SWT.NULL);
80 final GridLayout layout = new GridLayout();
81 layout.numColumns = 1;
82 panel.setLayout(layout);
84 createDestinationGroup(panel);
85 createConfigGroup(panel);
86 setControl(panel);
87 checkPage();
90 @Override
91 public void setVisible(final boolean visible) {
92 if (visible) {
93 if (branchPage.isSourceRepoEmpty()) {
94 initialBranch.setEnabled(false);
96 revalidate();
98 super.setVisible(visible);
99 if (visible)
100 directoryText.setFocus();
103 private void checkPreviousPagesSelections() {
104 if (!sourcePage.selectionEquals(validatedRepoSelection)
105 || !branchPage.selectionEquals(validatedSelectedBranches,
106 validatedHEAD))
107 setPageComplete(false);
108 else
109 checkPage();
112 private void createDestinationGroup(final Composite parent) {
113 final Group g = createGroup(parent,
114 UIText.CloneDestinationPage_groupDestination);
116 newLabel(g, UIText.CloneDestinationPage_promptDirectory + ":"); //$NON-NLS-1$
117 final Composite p = new Composite(g, SWT.NONE);
118 final GridLayout grid = new GridLayout();
119 grid.numColumns = 2;
120 p.setLayout(grid);
121 p.setLayoutData(createFieldGridData());
122 directoryText = new Text(p, SWT.BORDER);
123 directoryText.setLayoutData(createFieldGridData());
124 directoryText.addModifyListener(new ModifyListener() {
125 public void modifyText(final ModifyEvent e) {
126 checkPage();
129 final Button b = new Button(p, SWT.PUSH);
130 b.setText(UIText.CloneDestinationPage_browseButton);
131 b.addSelectionListener(new SelectionAdapter() {
132 public void widgetSelected(final SelectionEvent e) {
133 final FileDialog d;
135 d = new FileDialog(getShell(), SWT.APPLICATION_MODAL | SWT.SAVE);
136 if (directoryText.getText().length() > 0) {
137 final File file = new File(directoryText.getText())
138 .getAbsoluteFile();
139 d.setFilterPath(file.getParent());
140 d.setFileName(file.getName());
142 final String r = d.open();
143 if (r != null)
144 directoryText.setText(r);
148 newLabel(g, UIText.CloneDestinationPage_promptInitialBranch + ":"); //$NON-NLS-1$
149 initialBranch = new Combo(g, SWT.DROP_DOWN | SWT.READ_ONLY);
150 initialBranch.setLayoutData(createFieldGridData());
151 initialBranch.addSelectionListener(new SelectionAdapter() {
152 @Override
153 public void widgetSelected(final SelectionEvent e) {
154 checkPage();
159 private void createConfigGroup(final Composite parent) {
160 final Group g = createGroup(parent,
161 UIText.CloneDestinationPage_groupConfiguration);
163 newLabel(g, UIText.CloneDestinationPage_promptRemoteName + ":"); //$NON-NLS-1$
164 remoteText = new Text(g, SWT.BORDER);
165 remoteText.setText(Constants.DEFAULT_REMOTE_NAME);
166 remoteText.setLayoutData(createFieldGridData());
167 remoteText.addModifyListener(new ModifyListener() {
168 public void modifyText(ModifyEvent e) {
169 checkPage();
174 private static Group createGroup(final Composite parent, final String text) {
175 final Group g = new Group(parent, SWT.NONE);
176 final GridLayout layout = new GridLayout();
177 layout.numColumns = 2;
178 g.setLayout(layout);
179 g.setText(text);
180 final GridData gd = new GridData();
181 gd.grabExcessHorizontalSpace = true;
182 gd.horizontalAlignment = SWT.FILL;
183 g.setLayoutData(gd);
184 return g;
187 private static void newLabel(final Group g, final String text) {
188 new Label(g, SWT.NULL).setText(text);
191 private static GridData createFieldGridData() {
192 return new GridData(SWT.FILL, SWT.DEFAULT, true, false);
196 * @return location the user wants to store this repository.
198 public File getDestinationFile() {
199 return new File(directoryText.getText());
203 * @return initial branch selected (includes refs/heads prefix).
205 public String getInitialBranch() {
206 final int ix = initialBranch.getSelectionIndex();
207 if (ix < 0)
208 return Constants.R_HEADS + Constants.MASTER;
209 return Constants.R_HEADS + initialBranch.getItem(ix);
213 * @return remote name
215 public String getRemote() {
216 return remoteText.getText();
220 * Check internal state for page completion status.
222 private void checkPage() {
223 final String dstpath = directoryText.getText();
224 if (dstpath.length() == 0) {
225 setErrorMessage(NLS.bind(UIText.CloneDestinationPage_fieldRequired,
226 UIText.CloneDestinationPage_promptDirectory));
227 setPageComplete(false);
228 return;
230 final File absoluteFile = new File(dstpath).getAbsoluteFile();
231 if (!isEmptyDir(absoluteFile)) {
232 setErrorMessage(NLS.bind(
233 UIText.CloneDestinationPage_errorNotEmptyDir, absoluteFile
234 .getPath()));
235 setPageComplete(false);
236 return;
239 if (!canCreateSubdir(absoluteFile.getParentFile())) {
240 setErrorMessage(NLS.bind(UIText.GitCloneWizard_errorCannotCreate,
241 absoluteFile.getPath()));
242 setPageComplete(false);
243 return;
245 if (!branchPage.isSourceRepoEmpty()
246 && initialBranch.getSelectionIndex() < 0) {
247 setErrorMessage(NLS.bind(UIText.CloneDestinationPage_fieldRequired,
248 UIText.CloneDestinationPage_promptInitialBranch));
249 setPageComplete(false);
250 return;
252 if (remoteText.getText().length() == 0) {
253 setErrorMessage(NLS.bind(UIText.CloneDestinationPage_fieldRequired,
254 UIText.CloneDestinationPage_promptRemoteName));
255 setPageComplete(false);
256 return;
259 setErrorMessage(null);
260 setPageComplete(true);
263 private static boolean isEmptyDir(final File dir) {
264 if (!dir.exists())
265 return true;
266 if (!dir.isDirectory())
267 return false;
268 return dir.listFiles().length == 0;
271 // this is actually just an optimistic heuristic - should be named
272 // isThereHopeThatCanCreateSubdir() as probably there is no 100% reliable
273 // way to check that in Java for Windows
274 private static boolean canCreateSubdir(final File parent) {
275 if (parent == null)
276 return true;
277 if (parent.exists())
278 return parent.isDirectory() && parent.canWrite();
279 return canCreateSubdir(parent.getParentFile());
282 private void revalidate() {
283 if (sourcePage.selectionEquals(validatedRepoSelection)
284 && branchPage.selectionEquals(validatedSelectedBranches,
285 validatedHEAD)) {
286 checkPage();
287 return;
290 if (!sourcePage.selectionEquals(validatedRepoSelection)) {
291 validatedRepoSelection = sourcePage.getSelection();
292 // update repo-related selection only if it changed
293 final String n = validatedRepoSelection.getURI().getHumanishName();
294 setDescription(NLS.bind(UIText.CloneDestinationPage_description, n));
295 directoryText.setText(new File(ResourcesPlugin.getWorkspace()
296 .getRoot().getRawLocation().toFile(), n).getAbsolutePath());
299 validatedSelectedBranches = branchPage.getSelectedBranches();
300 validatedHEAD = branchPage.getHEAD();
302 initialBranch.removeAll();
303 final Ref head = branchPage.getHEAD();
304 int newix = 0;
305 for (final Ref r : branchPage.getSelectedBranches()) {
306 String name = r.getName();
307 if (name.startsWith(Constants.R_HEADS))
308 name = name.substring((Constants.R_HEADS).length());
309 if (head != null && head.getName().equals(r.getName()))
310 newix = initialBranch.getItemCount();
311 initialBranch.add(name);
313 initialBranch.select(newix);
314 checkPage();