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 * See LICENSE for the full license text, also available.
10 *******************************************************************************/
11 package org
.spearce
.egit
.ui
.internal
.clone
;
14 import java
.util
.List
;
16 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
17 import org
.eclipse
.jface
.wizard
.WizardPage
;
18 import org
.eclipse
.osgi
.util
.NLS
;
19 import org
.eclipse
.swt
.SWT
;
20 import org
.eclipse
.swt
.events
.ModifyEvent
;
21 import org
.eclipse
.swt
.events
.ModifyListener
;
22 import org
.eclipse
.swt
.events
.SelectionAdapter
;
23 import org
.eclipse
.swt
.events
.SelectionEvent
;
24 import org
.eclipse
.swt
.layout
.GridData
;
25 import org
.eclipse
.swt
.layout
.GridLayout
;
26 import org
.eclipse
.swt
.widgets
.Button
;
27 import org
.eclipse
.swt
.widgets
.Combo
;
28 import org
.eclipse
.swt
.widgets
.Composite
;
29 import org
.eclipse
.swt
.widgets
.FileDialog
;
30 import org
.eclipse
.swt
.widgets
.Group
;
31 import org
.eclipse
.swt
.widgets
.Label
;
32 import org
.eclipse
.swt
.widgets
.Text
;
33 import org
.spearce
.egit
.ui
.UIText
;
34 import org
.spearce
.egit
.ui
.internal
.components
.RepositorySelection
;
35 import org
.spearce
.egit
.ui
.internal
.components
.RepositorySelectionPage
;
36 import org
.spearce
.egit
.ui
.internal
.components
.SelectionChangeListener
;
37 import org
.spearce
.jgit
.lib
.Constants
;
38 import org
.spearce
.jgit
.lib
.Ref
;
41 * Wizard page that allows the user entering the location of a repository to be
44 class CloneDestinationPage
extends WizardPage
{
45 private final RepositorySelectionPage sourcePage
;
47 private final SourceBranchPage branchPage
;
49 private RepositorySelection validatedRepoSelection
;
51 private List
<Ref
> validatedSelectedBranches
;
53 private Ref validatedHEAD
;
55 private Combo initialBranch
;
57 private Text directoryText
;
59 private Text remoteText
;
61 Button showImportWizard
;
63 String alreadyClonedInto
;
65 CloneDestinationPage(final RepositorySelectionPage sp
,
66 final SourceBranchPage bp
) {
67 super(CloneDestinationPage
.class.getName());
70 setTitle(UIText
.CloneDestinationPage_title
);
72 final SelectionChangeListener listener
= new SelectionChangeListener() {
73 public void selectionChanged() {
74 checkPreviousPagesSelections();
77 sourcePage
.addSelectionListener(listener
);
78 branchPage
.addSelectionListener(listener
);
81 public void createControl(final Composite parent
) {
82 final Composite panel
= new Composite(parent
, SWT
.NULL
);
83 final GridLayout layout
= new GridLayout();
84 layout
.numColumns
= 1;
85 panel
.setLayout(layout
);
87 createDestinationGroup(panel
);
88 createConfigGroup(panel
);
89 createWorkbenchGroup(panel
);
95 public void setVisible(final boolean visible
) {
98 super.setVisible(visible
);
100 directoryText
.setFocus();
103 private void checkPreviousPagesSelections() {
104 if (!sourcePage
.selectionEquals(validatedRepoSelection
)
105 || !branchPage
.selectionEquals(validatedSelectedBranches
,
107 setPageComplete(false);
112 private void createDestinationGroup(final Composite parent
) {
113 final Group g
= createGroup(parent
,
114 UIText
.CloneDestinationPage_groupDestination
);
116 newLabel(g
, UIText
.CloneDestinationPage_promptDirectory
+ ":");
117 final Composite p
= new Composite(g
, SWT
.NONE
);
118 final GridLayout grid
= new GridLayout();
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
) {
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
) {
135 d
= new FileDialog(getShell(), SWT
.APPLICATION_MODAL
| SWT
.SAVE
);
136 if (directoryText
.getText().length() > 0) {
137 final File file
= new File(directoryText
.getText())
139 d
.setFilterPath(file
.getParent());
140 d
.setFileName(file
.getName());
142 final String r
= d
.open();
144 directoryText
.setText(r
);
148 newLabel(g
, UIText
.CloneDestinationPage_promptInitialBranch
+ ":");
149 initialBranch
= new Combo(g
, SWT
.DROP_DOWN
| SWT
.READ_ONLY
);
150 initialBranch
.setLayoutData(createFieldGridData());
151 initialBranch
.addSelectionListener(new SelectionAdapter() {
153 public void widgetSelected(final SelectionEvent e
) {
159 private void createConfigGroup(final Composite parent
) {
160 final Group g
= createGroup(parent
,
161 UIText
.CloneDestinationPage_groupConfiguration
);
163 newLabel(g
, UIText
.CloneDestinationPage_promptRemoteName
+ ":");
164 remoteText
= new Text(g
, SWT
.BORDER
);
165 remoteText
.setText("origin");
166 remoteText
.setLayoutData(createFieldGridData());
167 remoteText
.addModifyListener(new ModifyListener() {
168 public void modifyText(ModifyEvent e
) {
174 private void createWorkbenchGroup(Composite parent
) {
175 final Group g
= createGroup(parent
, UIText
.CloneDestinationPage_workspaceImport
);
176 showImportWizard
= new Button(g
, SWT
.CHECK
);
177 showImportWizard
.setSelection(true);
178 showImportWizard
.setText(UIText
.CloneDestinationPage_importProjectsAfterClone
);
179 showImportWizard
.setLayoutData(createFieldGridData());
180 showImportWizard
.addSelectionListener(new SelectionAdapter() {
182 public void widgetSelected(SelectionEvent e
) {
188 private static Group
createGroup(final Composite parent
, final String text
) {
189 final Group g
= new Group(parent
, SWT
.NONE
);
190 final GridLayout layout
= new GridLayout();
191 layout
.numColumns
= 2;
194 final GridData gd
= new GridData();
195 gd
.grabExcessHorizontalSpace
= true;
196 gd
.horizontalAlignment
= SWT
.FILL
;
201 private static void newLabel(final Group g
, final String text
) {
202 new Label(g
, SWT
.NULL
).setText(text
);
205 private static GridData
createFieldGridData() {
206 return new GridData(SWT
.FILL
, SWT
.DEFAULT
, true, false);
210 * @return location the user wants to store this repository.
212 public File
getDestinationFile() {
213 return new File(directoryText
.getText());
217 * @return initial branch selected (includes refs/heads prefix).
219 public String
getInitialBranch() {
220 final int ix
= initialBranch
.getSelectionIndex();
222 return Constants
.R_HEADS
+ Constants
.MASTER
;
223 return Constants
.R_HEADS
+ initialBranch
.getItem(ix
);
227 * @return remote name
229 public String
getRemote() {
230 return remoteText
.getText();
234 * Check internal state for page completion status.
236 private void checkPage() {
237 final String dstpath
= directoryText
.getText();
238 if (dstpath
.length() == 0) {
239 setErrorMessage(NLS
.bind(UIText
.CloneDestinationPage_fieldRequired
,
240 UIText
.CloneDestinationPage_promptDirectory
));
241 setPageComplete(false);
244 final File absoluteFile
= new File(dstpath
).getAbsoluteFile();
245 if (!absoluteFile
.getAbsolutePath().equals(alreadyClonedInto
)
246 && !isEmptyDir(absoluteFile
)) {
247 setErrorMessage(NLS
.bind(
248 UIText
.CloneDestinationPage_errorNotEmptyDir
, absoluteFile
250 setPageComplete(false);
254 if (!canCreateSubdir(absoluteFile
.getParentFile())) {
255 setErrorMessage(NLS
.bind(UIText
.GitCloneWizard_errorCannotCreate
,
256 absoluteFile
.getPath()));
257 setPageComplete(false);
260 if (initialBranch
.getSelectionIndex() < 0) {
261 setErrorMessage(NLS
.bind(UIText
.CloneDestinationPage_fieldRequired
,
262 UIText
.CloneDestinationPage_promptInitialBranch
));
263 setPageComplete(false);
266 if (remoteText
.getText().length() == 0) {
267 setErrorMessage(NLS
.bind(UIText
.CloneDestinationPage_fieldRequired
,
268 UIText
.CloneDestinationPage_promptRemoteName
));
269 setPageComplete(false);
273 setErrorMessage(null);
274 setPageComplete(true);
277 private static boolean isEmptyDir(final File dir
) {
280 if (!dir
.isDirectory())
282 return dir
.listFiles().length
== 0;
285 // this is actually just an optimistic heuristic - should be named
286 // isThereHopeThatCanCreateSubdir() as probably there is no 100% reliable
287 // way to check that in Java for Windows
288 private static boolean canCreateSubdir(final File parent
) {
292 return parent
.isDirectory() && parent
.canWrite();
293 return canCreateSubdir(parent
.getParentFile());
296 private void revalidate() {
297 if (sourcePage
.selectionEquals(validatedRepoSelection
)
298 && branchPage
.selectionEquals(validatedSelectedBranches
,
304 if (!sourcePage
.selectionEquals(validatedRepoSelection
)) {
305 validatedRepoSelection
= sourcePage
.getSelection();
306 // update repo-related selection only if it changed
307 final String n
= getSuggestedName();
308 setDescription(NLS
.bind(UIText
.CloneDestinationPage_description
, n
));
309 directoryText
.setText(new File(ResourcesPlugin
.getWorkspace()
310 .getRoot().getRawLocation().toFile(), n
).getAbsolutePath());
313 validatedSelectedBranches
= branchPage
.getSelectedBranches();
314 validatedHEAD
= branchPage
.getHEAD();
316 initialBranch
.removeAll();
317 final Ref head
= branchPage
.getHEAD();
319 for (final Ref r
: branchPage
.getSelectedBranches()) {
320 String name
= r
.getName();
321 if (name
.startsWith(Constants
.R_HEADS
))
322 name
= name
.substring((Constants
.R_HEADS
).length());
323 if (head
!= null && head
.getName().equals(r
.getName()))
324 newix
= initialBranch
.getItemCount();
325 initialBranch
.add(name
);
327 initialBranch
.select(newix
);
331 private String
getSuggestedName() {
332 String path
= validatedRepoSelection
.getURI().getPath();
333 int s
= path
.lastIndexOf('/');
335 path
= path
.substring(s
+ 1);
336 if (path
.endsWith(".git"))
337 path
= path
.substring(0, path
.length() - 4);
342 public boolean canFlipToNextPage() {
343 return super.canFlipToNextPage() && showImportWizard
.getSelection();