Add descriptive message to directory browsers
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / sharing / ExistingOrNewPage.java
blob9f4672c7847bf2c93b9cd072e3ae85d6cb1ff76a
1 /*******************************************************************************
2 * Copyright (C) 2009, 2013 Robin Rosenberg and others.
3 * Copyright (C) 2009, Mykola Nikishov <mn@mn.com.ua>
4 * Copyright (C) 2011, Mathias Kinzler <mathias.kinzler@sap.com>
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal.sharing;
13 import java.io.File;
14 import java.io.IOException;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.Map;
20 import org.eclipse.core.resources.IProject;
21 import org.eclipse.core.resources.IResource;
22 import org.eclipse.core.resources.ResourcesPlugin;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IPath;
25 import org.eclipse.core.runtime.NullProgressMonitor;
26 import org.eclipse.core.runtime.Path;
27 import org.eclipse.egit.core.RepositoryUtil;
28 import org.eclipse.egit.core.project.RepositoryFinder;
29 import org.eclipse.egit.core.project.RepositoryMapping;
30 import org.eclipse.egit.ui.Activator;
31 import org.eclipse.egit.ui.internal.UIIcons;
32 import org.eclipse.egit.ui.internal.UIText;
33 import org.eclipse.egit.ui.internal.repository.NewRepositoryWizard;
34 import org.eclipse.jface.dialogs.Dialog;
35 import org.eclipse.jface.dialogs.IMessageProvider;
36 import org.eclipse.jface.dialogs.MessageDialog;
37 import org.eclipse.jface.layout.GridDataFactory;
38 import org.eclipse.jface.layout.GridLayoutFactory;
39 import org.eclipse.jface.viewers.ArrayContentProvider;
40 import org.eclipse.jface.viewers.CheckStateChangedEvent;
41 import org.eclipse.jface.viewers.CheckboxTableViewer;
42 import org.eclipse.jface.viewers.CheckboxTreeViewer;
43 import org.eclipse.jface.viewers.ComboViewer;
44 import org.eclipse.jface.viewers.ICheckStateListener;
45 import org.eclipse.jface.viewers.ISelection;
46 import org.eclipse.jface.viewers.IStructuredSelection;
47 import org.eclipse.jface.viewers.StructuredSelection;
48 import org.eclipse.jface.viewers.ViewerComparator;
49 import org.eclipse.jface.window.Window;
50 import org.eclipse.jface.wizard.WizardDialog;
51 import org.eclipse.jface.wizard.WizardPage;
52 import org.eclipse.jgit.lib.Constants;
53 import org.eclipse.jgit.lib.ObjectId;
54 import org.eclipse.jgit.lib.Repository;
55 import org.eclipse.jgit.lib.RepositoryBuilder;
56 import org.eclipse.jgit.revwalk.RevCommit;
57 import org.eclipse.jgit.revwalk.RevTree;
58 import org.eclipse.jgit.revwalk.RevWalk;
59 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
60 import org.eclipse.jgit.treewalk.TreeWalk;
61 import org.eclipse.osgi.util.NLS;
62 import org.eclipse.swt.SWT;
63 import org.eclipse.swt.events.ModifyEvent;
64 import org.eclipse.swt.events.ModifyListener;
65 import org.eclipse.swt.events.SelectionAdapter;
66 import org.eclipse.swt.events.SelectionEvent;
67 import org.eclipse.swt.layout.GridData;
68 import org.eclipse.swt.layout.GridLayout;
69 import org.eclipse.swt.widgets.Button;
70 import org.eclipse.swt.widgets.Combo;
71 import org.eclipse.swt.widgets.Composite;
72 import org.eclipse.swt.widgets.DirectoryDialog;
73 import org.eclipse.swt.widgets.Event;
74 import org.eclipse.swt.widgets.Label;
75 import org.eclipse.swt.widgets.Listener;
76 import org.eclipse.swt.widgets.Table;
77 import org.eclipse.swt.widgets.TableColumn;
78 import org.eclipse.swt.widgets.TableItem;
79 import org.eclipse.swt.widgets.Text;
80 import org.eclipse.swt.widgets.Tree;
81 import org.eclipse.swt.widgets.TreeColumn;
82 import org.eclipse.swt.widgets.TreeItem;
83 import org.eclipse.ui.PlatformUI;
84 import org.eclipse.ui.ide.IDE.SharedImages;
86 /**
87 * Wizard page for connecting projects to Git repositories.
89 class ExistingOrNewPage extends WizardPage {
91 private final SharingWizard myWizard;
93 private Button createRepo;
95 private Tree tree;
97 private CheckboxTreeViewer viewer;
99 private Text repositoryToCreate;
101 private IPath minumumPath;
103 private Label dotGitSegment;
105 private Composite externalComposite;
107 private Composite parentRepoComposite;
109 private Text workDir;
111 private Text relPath;
113 private Button browseRepository;
115 private Repository selectedRepository;
117 private CheckboxTableViewer projectMoveViewer;
119 private final MoveProjectsLabelProvider moveProjectsLabelProvider = new MoveProjectsLabelProvider();
121 private boolean internalMode = false;
123 ExistingOrNewPage(SharingWizard w) {
124 super(ExistingOrNewPage.class.getName());
125 setTitle(UIText.ExistingOrNewPage_title);
126 setImageDescriptor(UIIcons.WIZBAN_CONNECT_REPO);
127 this.myWizard = w;
130 @Override
131 public void createControl(Composite parent) {
132 final RepositoryUtil util = Activator.getDefault().getRepositoryUtil();
133 Composite main = new Composite(parent, SWT.NONE);
134 // use zero spacing to save some real estate here
135 GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(main);
137 final Button internalModeButton = new Button(main, SWT.CHECK);
138 internalModeButton
139 .setText(UIText.ExistingOrNewPage_InternalModeCheckbox);
140 internalModeButton
141 .setToolTipText(UIText.ExistingOrNewPage_CreationInWorkspaceWarningTooltip);
142 internalModeButton.addSelectionListener(new SelectionAdapter() {
143 @Override
144 public void widgetSelected(SelectionEvent e) {
145 internalMode = internalModeButton.getSelection();
146 updateControls();
150 externalComposite = new Composite(main, SWT.NONE);
151 GridDataFactory.fillDefaults().grab(true, true)
152 .applyTo(externalComposite);
153 externalComposite.setLayout(new GridLayout(3, false));
155 new Label(externalComposite, SWT.NONE)
156 .setText(UIText.ExistingOrNewPage_ExistingRepositoryLabel);
157 final Combo existingRepoCombo = new Combo(externalComposite,
158 SWT.READ_ONLY);
159 GridDataFactory.fillDefaults().grab(true, false)
160 .applyTo(existingRepoCombo);
161 final ComboViewer v = new ComboViewer(existingRepoCombo);
162 v.setContentProvider(new RepoComboContentProvider());
163 v.setLabelProvider(new RepoComboLabelProvider());
164 v.setInput(new Object());
165 // the default ViewerSorter seems to do the right thing
166 // i.e. sort as String
167 v.setComparator(new ViewerComparator());
169 existingRepoCombo.addSelectionListener(new SelectionAdapter() {
170 @Override
171 public void widgetSelected(SelectionEvent e) {
172 selectedRepository = null;
173 IStructuredSelection sel = (IStructuredSelection) v
174 .getSelection();
175 setRepository((Repository) sel.getFirstElement());
176 updateControls();
180 Button createRepoWizard = new Button(externalComposite, SWT.PUSH);
181 createRepoWizard.setText(UIText.ExistingOrNewPage_CreateRepositoryButton);
182 createRepoWizard.addSelectionListener(new SelectionAdapter() {
183 @Override
184 public void widgetSelected(SelectionEvent e) {
185 NewRepositoryWizard wiz = new NewRepositoryWizard(true);
186 if (new WizardDialog(getShell(), wiz).open() == Window.OK) {
187 v.refresh();
188 selectedRepository = wiz.getCreatedRepository();
189 v.setSelection(new StructuredSelection(selectedRepository));
190 updateControls();
195 new Label(externalComposite, SWT.NONE)
196 .setText(UIText.ExistingOrNewPage_WorkingDirectoryLabel);
197 workDir = new Text(externalComposite, SWT.BORDER | SWT.READ_ONLY);
198 GridDataFactory.fillDefaults().grab(true, false).applyTo(workDir);
199 GridDataFactory.fillDefaults().applyTo(workDir);
200 // leave the space between the "Create" and "Browse" buttons empty (i.e.
201 // do not fill to the right border
202 new Label(externalComposite, SWT.NONE);
204 new Label(externalComposite, SWT.NONE)
205 .setText(UIText.ExistingOrNewPage_RelativePathLabel);
206 relPath = new Text(externalComposite, SWT.BORDER);
207 relPath.addModifyListener(new ModifyListener() {
208 @Override
209 public void modifyText(ModifyEvent e) {
210 updateControls();
214 GridDataFactory.fillDefaults().grab(true, false).applyTo(relPath);
215 browseRepository = new Button(externalComposite, SWT.PUSH);
216 browseRepository.setEnabled(false);
217 browseRepository
218 .setText(UIText.ExistingOrNewPage_BrowseRepositoryButton);
219 browseRepository.addSelectionListener(new SelectionAdapter() {
220 @Override
221 public void widgetSelected(SelectionEvent e) {
222 DirectoryDialog dlg = new DirectoryDialog(getShell());
223 dlg.setMessage(UIText.ExistingOrNewPage_title);
224 dlg.setFilterPath(selectedRepository.getWorkTree().getPath());
225 String directory = dlg.open();
226 if (directory != null) {
227 setRelativePath(directory);
228 updateControls();
233 Table projectMoveTable = new Table(externalComposite, SWT.MULTI
234 | SWT.FULL_SELECTION | SWT.CHECK | SWT.BORDER);
235 projectMoveViewer = new CheckboxTableViewer(projectMoveTable);
236 GridDataFactory.fillDefaults().span(3, 1).grab(true, true)
237 .applyTo(projectMoveTable);
239 TableColumn tc;
240 tc = new TableColumn(projectMoveTable, SWT.NONE);
241 tc.setText(UIText.ExistingOrNewPage_ProjectNameColumnHeader);
242 tc.setWidth(100);
244 tc = new TableColumn(projectMoveTable, SWT.NONE);
245 tc.setText(UIText.ExistingOrNewPage_CurrentLocationColumnHeader);
246 tc.setWidth(250);
248 tc = new TableColumn(projectMoveTable, SWT.NONE);
249 tc.setText(UIText.ExistingOrNewPage_NewLocationTargetHeader);
250 tc.setWidth(350);
252 projectMoveTable.setHeaderVisible(true);
253 projectMoveViewer
254 .setContentProvider(ArrayContentProvider.getInstance());
255 projectMoveViewer.setLabelProvider(moveProjectsLabelProvider);
256 projectMoveViewer.setInput(myWizard.projects);
257 projectMoveViewer.addCheckStateListener(new ICheckStateListener() {
258 @Override
259 public void checkStateChanged(CheckStateChangedEvent event) {
260 updateControls();
263 TableItem[] children = projectMoveViewer.getTable().getItems();
264 for (int i = 0; i < children.length; i++) {
265 TableItem item = children[i];
266 IProject data = (IProject) item.getData();
267 RepositoryFinder repositoryFinder = new RepositoryFinder(data);
268 repositoryFinder.setFindInChildren(false);
269 try {
270 Collection<RepositoryMapping> find = repositoryFinder
271 .find(new NullProgressMonitor());
272 if (find.size() != 1)
273 item.setChecked(true);
274 } catch (CoreException e1) {
275 item.setText(2, e1.getMessage());
279 parentRepoComposite = new Composite(main, SWT.NONE);
280 parentRepoComposite.setLayout(new GridLayout(3, false));
281 GridDataFactory.fillDefaults().grab(true, true)
282 .applyTo(parentRepoComposite);
284 tree = new Tree(parentRepoComposite, SWT.BORDER | SWT.MULTI
285 | SWT.FULL_SELECTION | SWT.CHECK);
286 viewer = new CheckboxTreeViewer(tree);
287 tree.setHeaderVisible(true);
288 tree.setLayout(new GridLayout());
289 tree.setLayoutData(GridDataFactory.fillDefaults().grab(true, true)
290 .span(3, 1).create());
291 viewer.addCheckStateListener(new ICheckStateListener() {
293 @Override
294 public void checkStateChanged(CheckStateChangedEvent event) {
295 if (event.getChecked()) {
296 ProjectAndRepo checkable = (ProjectAndRepo) event
297 .getElement();
298 for (TreeItem ti : tree.getItems()) {
299 if (ti.getItemCount() > 0
300 || ((ProjectAndRepo) ti.getData()).getRepo()
301 .equals("")) //$NON-NLS-1$
302 ti.setChecked(false);
303 for (TreeItem subTi : ti.getItems()) {
304 IProject project = ((ProjectAndRepo) subTi
305 .getData()).getProject();
306 if (checkable.getProject() != null
307 && !subTi.getData().equals(checkable)
308 && checkable.getProject().equals(project))
309 subTi.setChecked(false);
315 TreeColumn c1 = new TreeColumn(tree, SWT.NONE);
316 c1.setText(UIText.ExistingOrNewPage_HeaderProject);
317 c1.setWidth(100);
318 TreeColumn c2 = new TreeColumn(tree, SWT.NONE);
319 c2.setText(UIText.ExistingOrNewPage_HeaderLocation);
320 c2.setWidth(400);
321 TreeColumn c3 = new TreeColumn(tree, SWT.NONE);
322 c3.setText(UIText.ExistingOrNewPage_HeaderRepository);
323 c3.setWidth(200);
324 boolean allProjectsInExistingRepos = true;
325 for (IProject project : myWizard.projects) {
326 RepositoryFinder repositoryFinder = new RepositoryFinder(project);
327 repositoryFinder.setFindInChildren(false);
328 try {
329 Collection<RepositoryMapping> mappings;
330 mappings = repositoryFinder.find(new NullProgressMonitor());
331 Iterator<RepositoryMapping> mi = mappings.iterator();
332 RepositoryMapping m = mi.hasNext() ? mi.next() : null;
333 if (m == null) {
334 // no mapping found, enable repository creation
335 TreeItem treeItem = new TreeItem(tree, SWT.NONE);
336 updateProjectTreeItem(treeItem, project);
337 treeItem.setText(1, project.getLocation().toOSString());
338 treeItem.setText(2, ""); //$NON-NLS-1$
339 treeItem.setData(new ProjectAndRepo(project, "")); //$NON-NLS-1$
340 allProjectsInExistingRepos = false;
341 } else if (!mi.hasNext()) {
342 // exactly one mapping found
343 IPath path = m.getGitDirAbsolutePath();
344 if (path != null) {
345 TreeItem treeItem = new TreeItem(tree, SWT.NONE);
346 updateProjectTreeItem(treeItem, project);
347 treeItem.setText(1, project.getLocation().toOSString());
348 fillTreeItemWithGitDirectory(m, treeItem, path, false);
349 treeItem.setData(
350 new ProjectAndRepo(project, path.toOSString()));
351 treeItem.setChecked(true);
355 else {
356 IPath path = m.getGitDirAbsolutePath();
357 if (path != null) {
358 TreeItem treeItem = new TreeItem(tree, SWT.NONE);
359 updateProjectTreeItem(treeItem, project);
360 treeItem.setText(1, project.getLocation().toOSString());
361 treeItem.setData(new ProjectAndRepo(project, "")); //$NON-NLS-1$
363 TreeItem treeItem2 = new TreeItem(treeItem, SWT.NONE);
364 updateProjectTreeItem(treeItem2, project);
365 fillTreeItemWithGitDirectory(m, treeItem2, path, true);
366 treeItem2.setData(
367 new ProjectAndRepo(project,
368 path.toOSString()));
369 while (mi.hasNext()) { // fill in additional mappings
370 m = mi.next();
371 path = m.getGitDirAbsolutePath();
372 if(path != null){
373 treeItem2 = new TreeItem(treeItem, SWT.NONE);
374 updateProjectTreeItem(treeItem2, project);
375 fillTreeItemWithGitDirectory(m, treeItem2, path, true);
376 treeItem2.setData(new ProjectAndRepo(m.getContainer()
377 .getProject(), path.toOSString()));
380 treeItem.setExpanded(true);
382 allProjectsInExistingRepos = false;
384 } catch (CoreException e) {
385 TreeItem treeItem2 = new TreeItem(tree, SWT.BOLD | SWT.ITALIC);
386 treeItem2.setText(e.getMessage());
390 createRepo = new Button(parentRepoComposite, SWT.PUSH);
391 createRepo.setLayoutData(GridDataFactory.fillDefaults().create());
392 createRepo.setText(UIText.ExistingOrNewPage_CreateButton);
393 createRepo.addSelectionListener(new SelectionAdapter() {
394 @Override
395 public void widgetSelected(SelectionEvent e) {
396 File gitDir = new File(repositoryToCreate.getText(),
397 Constants.DOT_GIT);
398 try {
399 Repository repository = FileRepositoryBuilder
400 .create(gitDir);
401 repository.create();
402 for (IProject project : getProjects(false).keySet()) {
403 // If we don't refresh the project directories right
404 // now we won't later know that a .git directory
405 // exists within it and we won't mark the .git
406 // directory as a team-private member. Failure
407 // to do so might allow someone to delete
408 // the .git directory without us stopping them.
409 // (Half lie, we should optimize so we do not
410 // refresh when the .git is not within the project)
412 if (!gitDir.toString().contains("..")) //$NON-NLS-1$
413 project.refreshLocal(IResource.DEPTH_ONE,
414 new NullProgressMonitor());
416 util.addConfiguredRepository(gitDir);
417 } catch (IOException e1) {
418 String msg = NLS
419 .bind(UIText.ExistingOrNewPage_ErrorFailedToCreateRepository,
420 gitDir.toString());
421 org.eclipse.egit.ui.Activator.handleError(msg, e1, true);
422 } catch (CoreException e2) {
423 String msg = NLS
424 .bind(UIText.ExistingOrNewPage_ErrorFailedToRefreshRepository,
425 gitDir);
426 org.eclipse.egit.ui.Activator.handleError(msg, e2, true);
428 for (TreeItem ti : tree.getSelection()) {
429 IPath projectPath = new Path(ti.getText(1));
430 IPath gitPath = new Path(gitDir.toString());
431 IPath relative = gitPath.makeRelativeTo(projectPath);
432 ti.setText(2, relative.toOSString());
433 ((ProjectAndRepo) ti.getData()).repo = gitDir.toString();
434 ti.setChecked(true);
436 updateControls();
439 repositoryToCreate = new Text(parentRepoComposite, SWT.SINGLE
440 | SWT.BORDER);
441 repositoryToCreate.setLayoutData(GridDataFactory.fillDefaults()
442 .grab(true, false).span(1, 1).create());
443 repositoryToCreate.addListener(SWT.Modify, new Listener() {
444 @Override
445 public void handleEvent(Event e) {
446 if (repositoryToCreate.getText().equals("")) { //$NON-NLS-1$
447 createRepo.setEnabled(false);
448 return;
450 IPath fromOSString = Path.fromOSString(repositoryToCreate
451 .getText());
452 createRepo.setEnabled(minumumPath
453 .matchingFirstSegments(fromOSString) == fromOSString
454 .segmentCount());
457 dotGitSegment = new Label(parentRepoComposite, SWT.NONE);
458 dotGitSegment.setEnabled(false);
459 dotGitSegment.setText(File.separatorChar + Constants.DOT_GIT);
460 dotGitSegment.setLayoutData(GridDataFactory.fillDefaults()
461 .align(SWT.LEFT, SWT.CENTER).create());
463 tree.addSelectionListener(new SelectionAdapter() {
464 @Override
465 public void widgetSelected(SelectionEvent e) {
466 tree.select((TreeItem) e.item);
467 updateControls();
471 Dialog.applyDialogFont(main);
472 setControl(main);
474 if (allProjectsInExistingRepos) {
475 internalMode = true;
476 internalModeButton.setSelection(true);
477 updateControls();
481 private void updateProjectTreeItem(TreeItem item, IProject project) {
482 item.setImage(0,
483 PlatformUI.getWorkbench().getSharedImages()
484 .getImage(SharedImages.IMG_OBJ_PROJECT));
485 item.setText(0, project.getName());
488 protected void setRelativePath(String directory) {
489 IPath folderPath = new Path(directory).setDevice(null);
490 IPath workdirPath = new Path(this.selectedRepository.getWorkTree()
491 .getPath()).setDevice(null);
492 if (!workdirPath.isPrefixOf(folderPath)) {
493 MessageDialog.openError(getShell(),
494 UIText.ExistingOrNewPage_WrongPathErrorDialogTitle,
495 UIText.ExistingOrNewPage_WrongPathErrorDialogMessage);
496 return;
498 relPath.setText(folderPath.removeFirstSegments(
499 workdirPath.segmentCount()).toString());
502 protected void setRepository(Repository repository) {
503 if (repository == this.selectedRepository)
504 return;
505 this.selectedRepository = repository;
506 relPath.setText(""); //$NON-NLS-1$
509 @Override
510 public void setVisible(boolean visible) {
511 super.setVisible(visible);
512 if (visible)
513 updateControls();
516 private void fillTreeItemWithGitDirectory(RepositoryMapping m,
517 TreeItem treeItem, IPath gitDir, boolean isAlternative) {
518 if (m.getGitDir() == null)
519 treeItem.setText(2,
520 UIText.ExistingOrNewPage_SymbolicValueEmptyMapping);
521 else {
522 IPath relativePath = new Path(m.getGitDir());
523 if (isAlternative) {
524 IPath withoutLastSegment = relativePath.removeLastSegments(1);
525 IPath path;
526 if (withoutLastSegment.isEmpty())
527 path = Path.fromPortableString("."); //$NON-NLS-1$
528 else
529 path = withoutLastSegment;
530 treeItem.setText(0, path.toString());
532 treeItem.setText(2, relativePath.toOSString());
533 try {
534 IProject project = m.getContainer().getProject();
535 Repository repo = new RepositoryBuilder()
536 .setGitDir(gitDir.toFile()).build();
537 File workTree = repo.getWorkTree();
538 IPath workTreePath = Path.fromOSString(workTree
539 .getAbsolutePath());
540 if (workTreePath.isPrefixOf(project.getLocation())) {
541 IPath makeRelativeTo = project.getLocation()
542 .makeRelativeTo(workTreePath);
543 String repoRelativePath = makeRelativeTo
544 .append("/.project").toPortableString(); //$NON-NLS-1$
545 ObjectId headCommitId = repo.resolve(Constants.HEAD);
546 if (headCommitId != null) {
547 // Not an empty repo
548 try (RevWalk revWalk = new RevWalk(repo)) {
549 RevCommit headCommit = revWalk
550 .parseCommit(headCommitId);
551 RevTree headTree = headCommit.getTree();
552 TreeWalk projectInRepo = TreeWalk.forPath(repo,
553 repoRelativePath, headTree);
554 if (projectInRepo != null) {
555 // the .project file is tracked by this repo
556 treeItem.setChecked(true);
561 repo.close();
562 } catch (IOException e1) {
563 Activator
564 .logError(
565 UIText.ExistingOrNewPage_FailedToDetectRepositoryMessage,
566 e1);
571 protected void updateControls() {
572 setMessage(null);
573 setErrorMessage(null);
574 if (!internalMode) {
575 setDescription(UIText.ExistingOrNewPage_DescriptionExternalMode);
576 if (this.selectedRepository != null) {
577 workDir.setText(this.selectedRepository.getWorkTree().getPath());
578 String relativePath = relPath.getText();
579 File testFile = new File(this.selectedRepository.getWorkTree(),
580 relativePath);
581 if (!testFile.exists())
582 setMessage(
583 NLS.bind(
584 UIText.ExistingOrNewPage_FolderWillBeCreatedMessage,
585 relativePath), IMessageProvider.WARNING);
586 IPath targetPath = new Path(selectedRepository.getWorkTree()
587 .getPath());
588 targetPath = targetPath.append(relPath.getText());
589 moveProjectsLabelProvider.targetFolder = targetPath;
590 projectMoveViewer.refresh(true);
591 browseRepository.setEnabled(true);
592 for (Object checked : projectMoveViewer.getCheckedElements()) {
593 IProject prj = (IProject) checked;
594 IPath projectMoveTarget = targetPath.append(prj.getName());
595 boolean mustMove = !prj.getLocation().equals(
596 projectMoveTarget);
597 File targetTest = new File(projectMoveTarget.toOSString());
598 if (mustMove && targetTest.exists()) {
599 setErrorMessage(NLS
600 .bind(UIText.ExistingOrNewPage_ExistingTargetErrorMessage,
601 prj.getName()));
602 break;
604 File parent = targetTest.getParentFile();
605 while (parent != null) {
606 if (new File(parent, ".project").exists()) { //$NON-NLS-1$
607 setErrorMessage(NLS
608 .bind(UIText.ExistingOrNewPage_NestedProjectErrorMessage,
609 new String[] { prj.getName(),
610 targetTest.getPath(),
611 parent.getPath() }));
612 break;
614 parent = parent.getParentFile();
616 // break after the first error
617 if (getErrorMessage() != null)
618 break;
620 } else
621 workDir.setText(UIText.ExistingOrNewPage_NoRepositorySelectedMessage);
622 setPageComplete(getErrorMessage() == null
623 && selectedRepository != null
624 && projectMoveViewer.getCheckedElements().length > 0);
625 } else {
626 setDescription(UIText.ExistingOrNewPage_description);
627 IPath p = proposeNewRepositoryPath(tree.getSelection());
628 minumumPath = p;
629 if (p != null) {
630 repositoryToCreate.setText(p.toOSString());
631 } else {
632 repositoryToCreate.setText(""); //$NON-NLS-1$
634 createRepo.setEnabled(p != null);
635 repositoryToCreate.setEnabled(p != null);
636 dotGitSegment.setEnabled(p != null);
638 boolean pageComplete = viewer.getCheckedElements().length > 0;
639 for (Object checkedElement : viewer.getCheckedElements()) {
640 String path = ((ProjectAndRepo) checkedElement).getRepo();
641 if (((ProjectAndRepo) checkedElement).getRepo() != null
642 && path.equals("")) { //$NON-NLS-1$
643 pageComplete = false;
646 setPageComplete(pageComplete);
647 // provide a warning if Repository is created in workspace
648 for (IProject project : myWizard.projects) {
649 if (createRepo.isEnabled()
650 && ResourcesPlugin.getWorkspace().getRoot()
651 .getLocation()
652 .isPrefixOf(project.getLocation())) {
653 setMessage(
654 UIText.ExistingOrNewPage_RepoCreationInWorkspaceCreationWarning,
655 IMessageProvider.WARNING);
656 break;
661 externalComposite.setVisible(!internalMode);
662 parentRepoComposite.setVisible(internalMode);
663 GridData gd;
664 gd = (GridData) parentRepoComposite.getLayoutData();
665 gd.exclude = !internalMode;
667 gd = (GridData) externalComposite.getLayoutData();
668 gd.exclude = internalMode;
670 ((Composite) getControl()).layout(true);
673 private static IPath proposeNewRepositoryPath(TreeItem[] treeItems) {
674 IPath p = null;
675 for (TreeItem ti : treeItems) {
676 String gitDirParentCandidate = ti.getText(1);
677 if (gitDirParentCandidate.equals("")) //$NON-NLS-1$
678 continue;
679 if (ti.getItemCount() > 0)
680 if (hasRepositoryInOwnDirectory(ti.getItems()))
681 return null;
682 if (hasRepositoryInOwnDirectory(ti))
683 return null;
684 IPath thisPath = Path.fromOSString(gitDirParentCandidate);
685 if (p == null)
686 p = thisPath;
687 else {
688 int n = p.matchingFirstSegments(thisPath);
689 p = p.removeLastSegments(p.segmentCount() - n);
692 return p;
695 private static boolean hasRepositoryInOwnDirectory(TreeItem... items) {
696 for (TreeItem item : items)
697 if (".git".equals(item.getText(2))) //$NON-NLS-1$
698 return true;
699 return false;
703 * @param checked
704 * pass true to get the checked elements, false to get the
705 * selected elements
706 * @return map between project and repository root directory (converted to
707 * an absolute path) for all projects selected by user
709 public Map<IProject, File> getProjects(boolean checked) {
710 final Object[] elements;
711 if (!internalMode)
712 if (checked)
713 elements = projectMoveViewer.getCheckedElements();
714 else {
715 ISelection selection = viewer.getSelection();
716 elements = ((IStructuredSelection) selection).toArray();
718 else if (checked)
719 elements = viewer.getCheckedElements();
720 else {
721 ISelection selection = viewer.getSelection();
722 if (selection instanceof IStructuredSelection)
723 elements = ((IStructuredSelection) selection).toArray();
724 else
725 elements = new Object[0];
728 Map<IProject, File> ret = new HashMap<>(elements.length);
729 for (Object ti : elements) {
730 if (!internalMode) {
731 File workdir = selectedRepository.getWorkTree();
732 IProject project = (IProject) ti;
733 IPath targetLocation = new Path(relPath.getText())
734 .append(project.getName());
735 File targetFile = new File(workdir, targetLocation.toOSString());
736 ret.put(project, targetFile);
738 } else {
739 final IProject project = ((ProjectAndRepo) ti).getProject();
740 String path = ((ProjectAndRepo) ti).getRepo();
741 final IPath selectedRepo = Path.fromOSString(path);
742 IPath localPathToRepo = selectedRepo;
743 if (!selectedRepo.isAbsolute()) {
744 localPathToRepo = project.getLocation()
745 .append(selectedRepo);
747 ret.put(project, localPathToRepo.toFile());
750 return ret;
753 public boolean getInternalMode() {
754 return internalMode;
757 private static class ProjectAndRepo {
758 private IProject project;
760 private String repo;
762 public ProjectAndRepo(IProject project, String repo) {
763 this.project = project;
764 this.repo = repo;
767 public IProject getProject() {
768 return project;
771 public String getRepo() {
772 return repo;
776 public Repository getSelectedRepository() {
777 return selectedRepository;