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
;
14 import java
.io
.IOException
;
15 import java
.util
.Collection
;
16 import java
.util
.HashMap
;
17 import java
.util
.Iterator
;
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
;
87 * Wizard page for connecting projects to Git repositories.
89 class ExistingOrNewPage
extends WizardPage
{
91 private final SharingWizard myWizard
;
93 private Button createRepo
;
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
);
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
);
139 .setText(UIText
.ExistingOrNewPage_InternalModeCheckbox
);
141 .setToolTipText(UIText
.ExistingOrNewPage_CreationInWorkspaceWarningTooltip
);
142 internalModeButton
.addSelectionListener(new SelectionAdapter() {
144 public void widgetSelected(SelectionEvent e
) {
145 internalMode
= internalModeButton
.getSelection();
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
,
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() {
171 public void widgetSelected(SelectionEvent e
) {
172 selectedRepository
= null;
173 IStructuredSelection sel
= (IStructuredSelection
) v
175 setRepository((Repository
) sel
.getFirstElement());
180 Button createRepoWizard
= new Button(externalComposite
, SWT
.PUSH
);
181 createRepoWizard
.setText(UIText
.ExistingOrNewPage_CreateRepositoryButton
);
182 createRepoWizard
.addSelectionListener(new SelectionAdapter() {
184 public void widgetSelected(SelectionEvent e
) {
185 NewRepositoryWizard wiz
= new NewRepositoryWizard(true);
186 if (new WizardDialog(getShell(), wiz
).open() == Window
.OK
) {
188 selectedRepository
= wiz
.getCreatedRepository();
189 v
.setSelection(new StructuredSelection(selectedRepository
));
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() {
209 public void modifyText(ModifyEvent e
) {
214 GridDataFactory
.fillDefaults().grab(true, false).applyTo(relPath
);
215 browseRepository
= new Button(externalComposite
, SWT
.PUSH
);
216 browseRepository
.setEnabled(false);
218 .setText(UIText
.ExistingOrNewPage_BrowseRepositoryButton
);
219 browseRepository
.addSelectionListener(new SelectionAdapter() {
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
);
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
);
240 tc
= new TableColumn(projectMoveTable
, SWT
.NONE
);
241 tc
.setText(UIText
.ExistingOrNewPage_ProjectNameColumnHeader
);
244 tc
= new TableColumn(projectMoveTable
, SWT
.NONE
);
245 tc
.setText(UIText
.ExistingOrNewPage_CurrentLocationColumnHeader
);
248 tc
= new TableColumn(projectMoveTable
, SWT
.NONE
);
249 tc
.setText(UIText
.ExistingOrNewPage_NewLocationTargetHeader
);
252 projectMoveTable
.setHeaderVisible(true);
254 .setContentProvider(ArrayContentProvider
.getInstance());
255 projectMoveViewer
.setLabelProvider(moveProjectsLabelProvider
);
256 projectMoveViewer
.setInput(myWizard
.projects
);
257 projectMoveViewer
.addCheckStateListener(new ICheckStateListener() {
259 public void checkStateChanged(CheckStateChangedEvent event
) {
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);
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() {
294 public void checkStateChanged(CheckStateChangedEvent event
) {
295 if (event
.getChecked()) {
296 ProjectAndRepo checkable
= (ProjectAndRepo
) event
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
);
318 TreeColumn c2
= new TreeColumn(tree
, SWT
.NONE
);
319 c2
.setText(UIText
.ExistingOrNewPage_HeaderLocation
);
321 TreeColumn c3
= new TreeColumn(tree
, SWT
.NONE
);
322 c3
.setText(UIText
.ExistingOrNewPage_HeaderRepository
);
324 boolean allProjectsInExistingRepos
= true;
325 for (IProject project
: myWizard
.projects
) {
326 RepositoryFinder repositoryFinder
= new RepositoryFinder(project
);
327 repositoryFinder
.setFindInChildren(false);
329 Collection
<RepositoryMapping
> mappings
;
330 mappings
= repositoryFinder
.find(new NullProgressMonitor());
331 Iterator
<RepositoryMapping
> mi
= mappings
.iterator();
332 RepositoryMapping m
= mi
.hasNext() ? mi
.next() : 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();
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);
350 new ProjectAndRepo(project
, path
.toOSString()));
351 treeItem
.setChecked(true);
356 IPath path
= m
.getGitDirAbsolutePath();
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);
367 new ProjectAndRepo(project
,
369 while (mi
.hasNext()) { // fill in additional mappings
371 path
= m
.getGitDirAbsolutePath();
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() {
395 public void widgetSelected(SelectionEvent e
) {
396 File gitDir
= new File(repositoryToCreate
.getText(),
399 Repository repository
= FileRepositoryBuilder
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
) {
419 .bind(UIText
.ExistingOrNewPage_ErrorFailedToCreateRepository
,
421 org
.eclipse
.egit
.ui
.Activator
.handleError(msg
, e1
, true);
422 } catch (CoreException e2
) {
424 .bind(UIText
.ExistingOrNewPage_ErrorFailedToRefreshRepository
,
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();
439 repositoryToCreate
= new Text(parentRepoComposite
, SWT
.SINGLE
441 repositoryToCreate
.setLayoutData(GridDataFactory
.fillDefaults()
442 .grab(true, false).span(1, 1).create());
443 repositoryToCreate
.addListener(SWT
.Modify
, new Listener() {
445 public void handleEvent(Event e
) {
446 if (repositoryToCreate
.getText().equals("")) { //$NON-NLS-1$
447 createRepo
.setEnabled(false);
450 IPath fromOSString
= Path
.fromOSString(repositoryToCreate
452 createRepo
.setEnabled(minumumPath
453 .matchingFirstSegments(fromOSString
) == fromOSString
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() {
465 public void widgetSelected(SelectionEvent e
) {
466 tree
.select((TreeItem
) e
.item
);
471 Dialog
.applyDialogFont(main
);
474 if (allProjectsInExistingRepos
) {
476 internalModeButton
.setSelection(true);
481 private void updateProjectTreeItem(TreeItem item
, IProject project
) {
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
);
498 relPath
.setText(folderPath
.removeFirstSegments(
499 workdirPath
.segmentCount()).toString());
502 protected void setRepository(Repository repository
) {
503 if (repository
== this.selectedRepository
)
505 this.selectedRepository
= repository
;
506 relPath
.setText(""); //$NON-NLS-1$
510 public void setVisible(boolean visible
) {
511 super.setVisible(visible
);
516 private void fillTreeItemWithGitDirectory(RepositoryMapping m
,
517 TreeItem treeItem
, IPath gitDir
, boolean isAlternative
) {
518 if (m
.getGitDir() == null)
520 UIText
.ExistingOrNewPage_SymbolicValueEmptyMapping
);
522 IPath relativePath
= new Path(m
.getGitDir());
524 IPath withoutLastSegment
= relativePath
.removeLastSegments(1);
526 if (withoutLastSegment
.isEmpty())
527 path
= Path
.fromPortableString("."); //$NON-NLS-1$
529 path
= withoutLastSegment
;
530 treeItem
.setText(0, path
.toString());
532 treeItem
.setText(2, relativePath
.toOSString());
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
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) {
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);
562 } catch (IOException e1
) {
565 UIText
.ExistingOrNewPage_FailedToDetectRepositoryMessage
,
571 protected void updateControls() {
573 setErrorMessage(null);
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(),
581 if (!testFile
.exists())
584 UIText
.ExistingOrNewPage_FolderWillBeCreatedMessage
,
585 relativePath
), IMessageProvider
.WARNING
);
586 IPath targetPath
= new Path(selectedRepository
.getWorkTree()
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(
597 File targetTest
= new File(projectMoveTarget
.toOSString());
598 if (mustMove
&& targetTest
.exists()) {
600 .bind(UIText
.ExistingOrNewPage_ExistingTargetErrorMessage
,
604 File parent
= targetTest
.getParentFile();
605 while (parent
!= null) {
606 if (new File(parent
, ".project").exists()) { //$NON-NLS-1$
608 .bind(UIText
.ExistingOrNewPage_NestedProjectErrorMessage
,
609 new String
[] { prj
.getName(),
610 targetTest
.getPath(),
611 parent
.getPath() }));
614 parent
= parent
.getParentFile();
616 // break after the first error
617 if (getErrorMessage() != null)
621 workDir
.setText(UIText
.ExistingOrNewPage_NoRepositorySelectedMessage
);
622 setPageComplete(getErrorMessage() == null
623 && selectedRepository
!= null
624 && projectMoveViewer
.getCheckedElements().length
> 0);
626 setDescription(UIText
.ExistingOrNewPage_description
);
627 IPath p
= proposeNewRepositoryPath(tree
.getSelection());
630 repositoryToCreate
.setText(p
.toOSString());
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()
652 .isPrefixOf(project
.getLocation())) {
654 UIText
.ExistingOrNewPage_RepoCreationInWorkspaceCreationWarning
,
655 IMessageProvider
.WARNING
);
661 externalComposite
.setVisible(!internalMode
);
662 parentRepoComposite
.setVisible(internalMode
);
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
) {
675 for (TreeItem ti
: treeItems
) {
676 String gitDirParentCandidate
= ti
.getText(1);
677 if (gitDirParentCandidate
.equals("")) //$NON-NLS-1$
679 if (ti
.getItemCount() > 0)
680 if (hasRepositoryInOwnDirectory(ti
.getItems()))
682 if (hasRepositoryInOwnDirectory(ti
))
684 IPath thisPath
= Path
.fromOSString(gitDirParentCandidate
);
688 int n
= p
.matchingFirstSegments(thisPath
);
689 p
= p
.removeLastSegments(p
.segmentCount() - n
);
695 private static boolean hasRepositoryInOwnDirectory(TreeItem
... items
) {
696 for (TreeItem item
: items
)
697 if (".git".equals(item
.getText(2))) //$NON-NLS-1$
704 * pass true to get the checked elements, false to get the
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
;
713 elements
= projectMoveViewer
.getCheckedElements();
715 ISelection selection
= viewer
.getSelection();
716 elements
= ((IStructuredSelection
) selection
).toArray();
719 elements
= viewer
.getCheckedElements();
721 ISelection selection
= viewer
.getSelection();
722 if (selection
instanceof IStructuredSelection
)
723 elements
= ((IStructuredSelection
) selection
).toArray();
725 elements
= new Object
[0];
728 Map
<IProject
, File
> ret
= new HashMap
<>(elements
.length
);
729 for (Object ti
: elements
) {
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
);
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());
753 public boolean getInternalMode() {
757 private static class ProjectAndRepo
{
758 private IProject project
;
762 public ProjectAndRepo(IProject project
, String repo
) {
763 this.project
= project
;
767 public IProject
getProject() {
771 public String
getRepo() {
776 public Repository
getSelectedRepository() {
777 return selectedRepository
;