This adds an optional page for importing Eclipse style projects as part of the clone operation. The import page is a stripped down version of the project import wizard that comes with eclipse with the added ability to connect the projects to the Git team provider. Signed-off-by: Robin Rosenberg <robin.rosenberg@xxxxxxxxxx> --- org.spearce.egit.ui/META-INF/MANIFEST.MF | 1 + .../src/org/spearce/egit/ui/UIText.java | 42 + .../ui/internal/clone/CloneDestinationPage.java | 36 +- .../egit/ui/internal/clone/GitCloneWizard.java | 106 +++- .../ui/internal/clone/GitProjectsImportPage.java | 793 ++++++++++++++++++++ .../components/RepositorySelectionPage.java | 9 +- .../src/org/spearce/egit/ui/uitext.properties | 15 + 7 files changed, 979 insertions(+), 23 deletions(-) create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java diff --git a/org.spearce.egit.ui/META-INF/MANIFEST.MF b/org.spearce.egit.ui/META-INF/MANIFEST.MF index 092624f..420801b 100644 --- a/org.spearce.egit.ui/META-INF/MANIFEST.MF +++ b/org.spearce.egit.ui/META-INF/MANIFEST.MF @@ -19,6 +19,7 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.compare, org.spearce.jgit, org.spearce.egit.core, + org.eclipse.ui.ide, org.eclipse.jsch.ui;bundle-version="1.1.100" Eclipse-LazyStart: true Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java index b09cc10..124d7a0 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java @@ -17,6 +17,48 @@ */ public class UIText extends NLS { /** */ + public static String WizardProjectsImportPage_ImportProjectsTitle; + + /** */ + public static String WizardProjectsImportPage_ImportProjectsDescription; + + /** */ + public static String WizardProjectsImportPage_ProjectsListTitle; + + /** */ + public static String WizardProjectsImportPage_selectAll; + + /** */ + public static String WizardProjectsImportPage_deselectAll; + + /** */ + public static String WizardProjectsImportPage_projectLabel; + + /** */ + public static String WizardProjectsImportPage_SearchingMessage; + + /** */ + public static String WizardProjectsImportPage_ProcessingMessage; + + /** */ + public static String WizardProjectsImportPage_projectsInWorkspace; + + /** */ + public static String WizardProjectsImportPage_CheckingMessage; + + /** */ + public static String WizardProjectsImportPage_SelectDialogTitle; + + /** */ + public static String WizardProjectImportPage_errorMessage; + + /** */ + public static String WizardProjectsImportPage_CreateProjectsTask; + + /** */ + public static String WizardProjectsImportPage_enableGit; + + /** */ public static String SharingWizard_windowTitle; /** */ diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/CloneDestinationPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/CloneDestinationPage.java index 5173335..d017b60 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/CloneDestinationPage.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/CloneDestinationPage.java @@ -2,6 +2,7 @@ * Copyright (C) 2008, Roger C. Soares <rogersoares@xxxxxxxxxxxxxxxx> * Copyright (C) 2008, Shawn O. Pearce <spearce@xxxxxxxxxxx> * Copyright (C) 2008, Marek Zawirski <marek.zawirski@xxxxxxxxx> + * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@xxxxxxxxxx> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -57,12 +58,15 @@ private Text remoteText; + Button showImportWizard; + + String alreadyClonedInto; + CloneDestinationPage(final RepositorySelectionPage sp, final SourceBranchPage bp) { super(CloneDestinationPage.class.getName()); sourcePage = sp; branchPage = bp; - setTitle(UIText.CloneDestinationPage_title); final SelectionChangeListener listener = new SelectionChangeListener() { @@ -82,7 +86,7 @@ public void createControl(final Composite parent) { createDestinationGroup(panel); createConfigGroup(panel); - + createWorkbenchGroup(panel); setControl(panel); checkPage(); } @@ -92,6 +96,8 @@ public void setVisible(final boolean visible) { if (visible) revalidate(); super.setVisible(visible); + if (visible) + directoryText.setFocus(); } private void checkPreviousPagesSelections() { @@ -165,6 +171,20 @@ public void modifyText(ModifyEvent e) { }); } + private void createWorkbenchGroup(Composite parent) { + final Group g = createGroup(parent, "Workspace import"); + newLabel(g, "Import projects after clone"); + showImportWizard = new Button(g, SWT.CHECK); + showImportWizard.setSelection(true); + showImportWizard.setLayoutData(createFieldGridData()); + showImportWizard.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + checkPage(); + } + }); + } + private static Group createGroup(final Composite parent, final String text) { final Group g = new Group(parent, SWT.NONE); final GridLayout layout = new GridLayout(); @@ -222,9 +242,11 @@ setErrorMessage(NLS.bind(UIText.CloneDestinationPage_fieldRequired, return; } final File absoluteFile = new File(dstpath).getAbsoluteFile(); - if (!isEmptyDir(absoluteFile)) { - setErrorMessage(NLS.bind(UIText.CloneDestinationPage_errorNotEmptyDir, - absoluteFile.getPath())); + if (!absoluteFile.getAbsolutePath().equals(alreadyClonedInto) + && !isEmptyDir(absoluteFile)) { + setErrorMessage(NLS.bind( + UIText.CloneDestinationPage_errorNotEmptyDir, absoluteFile + .getPath())); setPageComplete(false); return; } @@ -316,4 +338,8 @@ private String getSuggestedName() { return path; } + @Override + public boolean canFlipToNextPage() { + return super.canFlipToNextPage() && showImportWizard.getSelection(); + } } \ No newline at end of file diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitCloneWizard.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitCloneWizard.java index a69dc52..114467f 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitCloneWizard.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitCloneWizard.java @@ -2,6 +2,7 @@ * Copyright (C) 2008, Roger C. Soares <rogersoares@xxxxxxxxxxxxxxxx> * Copyright (C) 2008, Shawn O. Pearce <spearce@xxxxxxxxxxx> * Copyright (C) 2008, Marek Zawirski <marek.zawirski@xxxxxxxxx> + * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@xxxxxxxxxx> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +19,13 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.wizard.Wizard; import org.eclipse.osgi.util.NLS; import org.eclipse.ui.IImportWizard; import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; import org.spearce.egit.core.op.CloneOperation; import org.spearce.egit.ui.Activator; import org.spearce.egit.ui.UIIcons; @@ -41,6 +44,8 @@ private CloneDestinationPage cloneDestination; + private GitProjectsImportPage importProject; + public void init(IWorkbench arg0, IStructuredSelection arg1) { setWindowTitle(UIText.GitCloneWizard_title); setDefaultPageImageDescriptor(UIIcons.WIZBAN_IMPORT_REPO); @@ -48,6 +53,46 @@ public void init(IWorkbench arg0, IStructuredSelection arg1) { cloneSource = new RepositorySelectionPage(true); validSource = new SourceBranchPage(cloneSource); cloneDestination = new CloneDestinationPage(cloneSource, validSource); + importProject = new GitProjectsImportPage() { + @Override + public void setVisible(boolean visible) { + if (visible) { + if (cloneDestination.alreadyClonedInto == null) { + performClone(false); + cloneDestination.alreadyClonedInto = cloneDestination + .getDestinationFile().getAbsolutePath(); + } + setProjectsList(cloneDestination.alreadyClonedInto); + } + super.setVisible(visible); + } + }; + } + + @Override + public boolean performCancel() { + if (cloneDestination.alreadyClonedInto != null) { + if (MessageDialog + .openQuestion(getShell(), "Aborting clone.", + "A complete clone was already made. Do you want to delete it?")) { + deleteRecursively(new File(cloneDestination.alreadyClonedInto)); + } + } + return true; + } + + private void deleteRecursively(File f) { + for (File i : f.listFiles()) { + if (i.isDirectory()) { + deleteRecursively(i); + } else { + if (!i.delete()) { + i.deleteOnExit(); + } + } + } + if (!f.delete()) + f.deleteOnExit(); } @Override @@ -55,10 +100,24 @@ public void addPages() { addPage(cloneSource); addPage(validSource); addPage(cloneDestination); + addPage(importProject); + } + + @Override + public boolean canFinish() { + return cloneDestination.isPageComplete() + && !cloneDestination.showImportWizard.getSelection() + || importProject.isPageComplete(); } @Override public boolean performFinish() { + if (!cloneDestination.showImportWizard.getSelection()) + return performClone(true); + return importProject.createProjects(); + } + + boolean performClone(boolean background) { final URIish uri = cloneSource.getSelection().getURI(); final boolean allSelected = validSource.isAllSelected(); final Collection<Ref> selectedBranches = validSource @@ -80,24 +139,37 @@ public boolean performFinish() { final CloneOperation op = new CloneOperation(uri, allSelected, selectedBranches, workdir, branch, remoteName); - final Job job = new Job(NLS.bind(UIText.GitCloneWizard_jobName, uri - .toString())) { - @Override - protected IStatus run(final IProgressMonitor monitor) { - try { - op.run(monitor); - return Status.OK_STATUS; - } catch (InterruptedException e) { - return Status.CANCEL_STATUS; - } catch (InvocationTargetException e) { - Throwable thr = e.getCause(); - return new Status(IStatus.ERROR, Activator.getPluginId(), - 0, thr.getMessage(), thr); + if (background) { + final Job job = new Job(NLS.bind(UIText.GitCloneWizard_jobName, uri + .toString())) { + @Override + protected IStatus run(final IProgressMonitor monitor) { + try { + op.run(monitor); + return Status.OK_STATUS; + } catch (InterruptedException e) { + return Status.CANCEL_STATUS; + } catch (InvocationTargetException e) { + Throwable thr = e.getCause(); + return new Status(IStatus.ERROR, Activator + .getPluginId(), 0, thr.getMessage(), thr); + } } + }; + job.setUser(true); + job.schedule(); + return true; + } else { + try { + PlatformUI.getWorkbench().getProgressService().run(false, true, + op); + return true; + } catch (Exception e) { + Activator.logError("Failed to clone", e); + MessageDialog.openError(getShell(), "Failed clone", e + .toString()); + return false; } - }; - job.setUser(true); - job.schedule(); - return true; + } } } diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java new file mode 100644 index 0000000..ece585a --- /dev/null +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/clone/GitProjectsImportPage.java @@ -0,0 +1,793 @@ +package org.spearce.egit.ui.internal.clone; + +/******************************************************************************* + * Copyright (c) 2004, 2008 IBM Corporation and others. + * Copyright (C) 2007, Martin Oberhuber (martin.oberhuber@xxxxxxxxxxxxx) + * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@xxxxxxxxxx> + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * See LICENSE for the full license text, also available. + *******************************************************************************/ + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; +import org.eclipse.ui.internal.ide.StatusUtil; +import org.eclipse.ui.internal.wizards.datatransfer.WizardProjectsImportPage; +import org.eclipse.ui.statushandlers.StatusManager; +import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider; +import org.spearce.egit.core.op.ConnectProviderOperation; +import org.spearce.egit.ui.Activator; +import org.spearce.egit.ui.UIText; + +/** + * The GitWizardProjectsImportPage is the page that allows the user to import + * projects from a particular location. This is a modified copy of + * {@link WizardProjectsImportPage} + */ +public class GitProjectsImportPage extends WizardPage { + + /** + * The name of the folder containing metadata information for the workspace. + */ + public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$ + + /** + * The import structure provider. + */ + private IImportStructureProvider structureProvider; + + class ProjectRecord { + File projectSystemFile; + + String projectName; + + Object parent; + + int level; + + IProjectDescription description; + + /** + * Create a record for a project based on the info in the file. + * + * @param file + */ + ProjectRecord(File file) { + projectSystemFile = file; + setProjectName(); + } + + /** + * @param parent + * The parent folder of the .project file + * @param level + * The number of levels deep in the provider the file is + */ + ProjectRecord(Object parent, int level) { + this.parent = parent; + this.level = level; + setProjectName(); + } + + /** + * Set the name of the project based on the projectFile. + */ + private void setProjectName() { + try { + // If we don't have the project name try again + if (projectName == null) { + IPath path = new Path(projectSystemFile.getPath()); + // if the file is in the default location, use the directory + // name as the project name + if (isDefaultLocation(path)) { + projectName = path.segment(path.segmentCount() - 2); + description = IDEWorkbenchPlugin.getPluginWorkspace() + .newProjectDescription(projectName); + } else { + description = IDEWorkbenchPlugin.getPluginWorkspace() + .loadProjectDescription(path); + projectName = description.getName(); + } + + } + } catch (CoreException e) { + // no good couldn't get the name + } + } + + /** + * Returns whether the given project description file path is in the + * default location for a project + * + * @param path + * The path to examine + * @return Whether the given path is the default location for a project + */ + private boolean isDefaultLocation(IPath path) { + // The project description file must at least be within the project, + // which is within the workspace location + if (path.segmentCount() < 2) + return false; + return path.removeLastSegments(2).toFile().equals( + Platform.getLocation().toFile()); + } + + /** + * Get the name of the project + * + * @return String + */ + public String getProjectName() { + return projectName; + } + + /** + * Gets the label to be used when rendering this project record in the + * UI. + * + * @return String the label + * @since 3.4 + */ + public String getProjectLabel() { + if (description == null) + return projectName; + + String path = projectSystemFile == null ? structureProvider + .getLabel(parent) : projectSystemFile.getParent(); + + return NLS.bind(UIText.WizardProjectsImportPage_projectLabel, + projectName, path); + } + } + + private CheckboxTreeViewer projectsList; + + private ProjectRecord[] selectedProjects = new ProjectRecord[0]; + + private IProject[] wsProjects; + + // The last selected path to minimize searches + private String lastPath; + + // The last time that the file or folder at the selected path was modified + // to mimize searches + private long lastModified; + + private Button shareCheckBox; + + private boolean share; + + /** + * Creates a new project creation wizard page. + */ + public GitProjectsImportPage() { + this("gitWizardExternalProjectsPage"); //$NON-NLS-1$ + } + + /** + * Create a new instance of the receiver. + * + * @param pageName + */ + public GitProjectsImportPage(String pageName) { + super(pageName); + setPageComplete(false); + setTitle(UIText.WizardProjectsImportPage_ImportProjectsTitle); + setDescription(UIText.WizardProjectsImportPage_ImportProjectsDescription); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets + * .Composite) + */ + public void createControl(Composite parent) { + + initializeDialogUnits(parent); + + Composite workArea = new Composite(parent, SWT.NONE); + setControl(workArea); + + workArea.setLayout(new GridLayout()); + workArea.setLayoutData(new GridData(GridData.FILL_BOTH + | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL)); + + createProjectsRoot(workArea); + createProjectsList(workArea); + createOptionsArea(workArea); + Dialog.applyDialogFont(workArea); + + } + + /** + * Create the area with the extra options. + * + * @param workArea + */ + private void createOptionsArea(Composite workArea) { + Composite optionsGroup = new Composite(workArea, SWT.NONE); + optionsGroup.setLayout(new GridLayout()); + optionsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + shareCheckBox = new Button(optionsGroup, SWT.CHECK); + shareCheckBox.setText(UIText.WizardProjectsImportPage_enableGit); + shareCheckBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + shareCheckBox.setSelection(share = true); + shareCheckBox.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + share = shareCheckBox.getSelection(); + } + }); + } + + /** + * Create the checkbox list for the found projects. + * + * @param workArea + */ + private void createProjectsList(Composite workArea) { + + Label title = new Label(workArea, SWT.NONE); + title.setText(UIText.WizardProjectsImportPage_ProjectsListTitle); + + Composite listComposite = new Composite(workArea, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginWidth = 0; + layout.makeColumnsEqualWidth = false; + listComposite.setLayout(layout); + + listComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.FILL_BOTH)); + + projectsList = new CheckboxTreeViewer(listComposite, SWT.BORDER); + GridData listData = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.FILL_BOTH); + projectsList.getControl().setLayoutData(listData); + + projectsList.setContentProvider(new ITreeContentProvider() { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java + * .lang.Object) + */ + public Object[] getChildren(Object parentElement) { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.IStructuredContentProvider#getElements + * (java.lang.Object) + */ + public Object[] getElements(Object inputElement) { + return getValidProjects(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java + * .lang.Object) + */ + public boolean hasChildren(Object element) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.ITreeContentProvider#getParent(java + * .lang.Object) + */ + public Object getParent(Object element) { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public void dispose() { + + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse + * .jface.viewers.Viewer, java.lang.Object, java.lang.Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, + Object newInput) { + } + + }); + + projectsList.setLabelProvider(new LabelProvider() { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object) + */ + public String getText(Object element) { + return ((ProjectRecord) element).getProjectLabel(); + } + }); + + projectsList.addCheckStateListener(new ICheckStateListener() { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged + * (org.eclipse.jface.viewers.CheckStateChangedEvent) + */ + public void checkStateChanged(CheckStateChangedEvent event) { + setPageComplete(projectsList.getCheckedElements().length > 0); + } + }); + + projectsList.setInput(this); + projectsList.setComparator(new ViewerComparator()); + createSelectionButtons(listComposite); + } + + /** + * Create the selection buttons in the listComposite. + * + * @param listComposite + */ + private void createSelectionButtons(Composite listComposite) { + Composite buttonsComposite = new Composite(listComposite, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + buttonsComposite.setLayout(layout); + + buttonsComposite.setLayoutData(new GridData( + GridData.VERTICAL_ALIGN_BEGINNING)); + + Button selectAll = new Button(buttonsComposite, SWT.PUSH); + selectAll.setText(UIText.WizardProjectsImportPage_selectAll); + selectAll.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + projectsList.setCheckedElements(selectedProjects); + setPageComplete(projectsList.getCheckedElements().length > 0); + } + }); + Dialog.applyDialogFont(selectAll); + setButtonLayoutData(selectAll); + + Button deselectAll = new Button(buttonsComposite, SWT.PUSH); + deselectAll.setText(UIText.WizardProjectsImportPage_deselectAll); + deselectAll.addSelectionListener(new SelectionAdapter() { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse + * .swt.events.SelectionEvent) + */ + public void widgetSelected(SelectionEvent e) { + + projectsList.setCheckedElements(new Object[0]); + setPageComplete(false); + } + }); + Dialog.applyDialogFont(deselectAll); + setButtonLayoutData(deselectAll); + + } + + /** + * Create the area where you select the root directory for the projects. + * + * @param workArea + * Composite + */ + private void createProjectsRoot(Composite workArea) { + + // project specification group + Composite projectGroup = new Composite(workArea, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + layout.makeColumnsEqualWidth = false; + layout.marginWidth = 0; + projectGroup.setLayout(layout); + projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + } + + /* + * (non-Javadoc) Method declared on IDialogPage. Set the focus on path + * fields when page becomes visible. + */ + public void setVisible(boolean visible) { + super.setVisible(visible); + } + + /** + * Update the list of projects based on path. + * + * @param path + */ + void setProjectsList(final String path) { + // on an empty path empty selectedProjects + if (path == null || path.length() == 0) { + setMessage(UIText.WizardProjectsImportPage_ImportProjectsDescription); + selectedProjects = new ProjectRecord[0]; + projectsList.refresh(true); + projectsList.setCheckedElements(selectedProjects); + setPageComplete(projectsList.getCheckedElements().length > 0); + lastPath = path; + return; + } + + final File directory = new File(path); + long modified = directory.lastModified(); + if (path.equals(lastPath) && lastModified == modified) { + // since the file/folder was not modified and the path did not + // change, no refreshing is required + return; + } + + lastPath = path; + lastModified = modified; + + try { + getContainer().run(true, true, new IRunnableWithProgress() { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.operation.IRunnableWithProgress#run(org + * .eclipse.core.runtime.IProgressMonitor) + */ + public void run(IProgressMonitor monitor) { + + monitor.beginTask( + UIText.WizardProjectsImportPage_SearchingMessage, + 100); + selectedProjects = new ProjectRecord[0]; + Collection files = new ArrayList(); + monitor.worked(10); + if (directory.isDirectory()) { + + if (!collectProjectFilesFromDirectory(files, directory, + null, monitor)) { + return; + } + Iterator filesIterator = files.iterator(); + selectedProjects = new ProjectRecord[files.size()]; + int index = 0; + monitor.worked(50); + monitor + .subTask(UIText.WizardProjectsImportPage_ProcessingMessage); + while (filesIterator.hasNext()) { + File file = (File) filesIterator.next(); + selectedProjects[index] = new ProjectRecord(file); + index++; + } + } else { + monitor.worked(60); + } + monitor.done(); + } + + }); + } catch (InvocationTargetException e) { + IDEWorkbenchPlugin.log(e.getMessage(), e); + } catch (InterruptedException e) { + // Nothing to do if the user interrupts. + } + + projectsList.refresh(true); + projectsList.setCheckedElements(getValidProjects()); + if (getValidProjects().length < selectedProjects.length) { + setMessage(UIText.WizardProjectsImportPage_projectsInWorkspace, + WARNING); + } else { + setMessage(UIText.WizardProjectsImportPage_ImportProjectsDescription); + } + setPageComplete(projectsList.getCheckedElements().length > 0); + } + + /** + * Collect the list of .project files that are under directory into files. + * + * @param files + * @param directory + * @param directoriesVisited + * Set of canonical paths of directories, used as recursion guard + * @param monitor + * The monitor to report to + * @return boolean <code>true</code> if the operation was completed. + */ + private boolean collectProjectFilesFromDirectory(Collection files, + File directory, Set directoriesVisited, IProgressMonitor monitor) { + + if (monitor.isCanceled()) { + return false; + } + monitor.subTask(NLS.bind( + UIText.WizardProjectsImportPage_CheckingMessage, directory + .getPath())); + File[] contents = directory.listFiles(); + if (contents == null) + return false; + + // Initialize recursion guard for recursive symbolic links + if (directoriesVisited == null) { + directoriesVisited = new HashSet(); + try { + directoriesVisited.add(directory.getCanonicalPath()); + } catch (IOException exception) { + StatusManager.getManager().handle( + StatusUtil.newStatus(IStatus.ERROR, exception + .getLocalizedMessage(), exception)); + } + } + + // first look for project description files + final String dotProject = IProjectDescription.DESCRIPTION_FILE_NAME; + for (int i = 0; i < contents.length; i++) { + File file = contents[i]; + if (file.isFile() && file.getName().equals(dotProject)) { + files.add(file); + // don't search sub-directories since we can't have nested + // projects + return true; + } + } + // no project description found, so recurse into sub-directories + for (int i = 0; i < contents.length; i++) { + if (contents[i].isDirectory()) { + if (!contents[i].getName().equals(METADATA_FOLDER)) { + try { + String canonicalPath = contents[i].getCanonicalPath(); + if (!directoriesVisited.add(canonicalPath)) { + // already been here --> do not recurse + continue; + } + } catch (IOException exception) { + StatusManager.getManager().handle( + StatusUtil.newStatus(IStatus.ERROR, exception + .getLocalizedMessage(), exception)); + + } + collectProjectFilesFromDirectory(files, contents[i], + directoriesVisited, monitor); + } + } + } + return true; + } + + /** + * Create the selected projects + * + * @return boolean <code>true</code> if all project creations were + * successful. + */ + boolean createProjects() { + final Object[] selected = projectsList.getCheckedElements(); + WorkspaceModifyOperation op = new WorkspaceModifyOperation() { + protected void execute(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + try { + monitor.beginTask("", selected.length); //$NON-NLS-1$ + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + for (int i = 0; i < selected.length; i++) { + createExistingProject((ProjectRecord) selected[i], + new SubProgressMonitor(monitor, 1)); + } + } finally { + monitor.done(); + } + } + }; + // run the new project creation operation + try { + getContainer().run(true, true, op); + } catch (InterruptedException e) { + return false; + } catch (InvocationTargetException e) { + // one of the steps resulted in a core exception + Throwable t = e.getTargetException(); + String message = UIText.WizardProjectImportPage_errorMessage; + IStatus status; + if (t instanceof CoreException) { + status = ((CoreException) t).getStatus(); + } else { + status = new Status(IStatus.ERROR, + IDEWorkbenchPlugin.IDE_WORKBENCH, 1, message, t); + } + Activator.logError(message, t); + ErrorDialog.openError(getShell(), message, null, status); + return false; + } + return true; + } + + /** + * Create the project described in record. If it is successful return true. + * + * @param record + * @param monitor + * @return boolean <code>true</code> if successful + * @throws InvocationTargetException + * @throws InterruptedException + */ + private boolean createExistingProject(final ProjectRecord record, + IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + String projectName = record.getProjectName(); + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + final IProject project = workspace.getRoot().getProject(projectName); + if (record.description == null) { + // error case + record.description = workspace.newProjectDescription(projectName); + IPath locationPath = new Path(record.projectSystemFile + .getAbsolutePath()); + + // If it is under the root use the default location + if (Platform.getLocation().isPrefixOf(locationPath)) { + record.description.setLocation(null); + } else { + record.description.setLocation(locationPath); + } + } else { + record.description.setName(projectName); + } + + try { + monitor.beginTask( + UIText.WizardProjectsImportPage_CreateProjectsTask, 100); + project.create(record.description, new SubProgressMonitor(monitor, + 30)); + int openTicks = share ? 50 : 70; + project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor( + monitor, openTicks)); + if (share) { + ConnectProviderOperation connectProviderOperation = new ConnectProviderOperation( + project, null); + connectProviderOperation + .run(new SubProgressMonitor(monitor, 20)); + } + } catch (CoreException e) { + throw new InvocationTargetException(e); + } finally { + monitor.done(); + } + + return true; + } + + /** + * Method used for test suite. + * + * @return CheckboxTreeViewer the viewer containing all the projects found + */ + public CheckboxTreeViewer getProjectsList() { + return projectsList; + } + + /** + * Retrieve all the projects in the current workspace. + * + * @return IProject[] array of IProject in the current workspace + */ + private IProject[] getProjectsInWorkspace() { + if (wsProjects == null) { + wsProjects = IDEWorkbenchPlugin.getPluginWorkspace().getRoot() + .getProjects(); + } + return wsProjects; + } + + /** + * Get the array of valid project records that can be imported from the + * source workspace or archive, selected by the user. If a project with the + * same name exists in both the source workspace and the current workspace, + * it will not appear in the list of projects to import and thus cannot be + * selected for import. + * + * Method declared public for test suite. + * + * @return ProjectRecord[] array of projects that can be imported into the + * workspace + */ + public ProjectRecord[] getValidProjects() { + List validProjects = new ArrayList(); + for (int i = 0; i < selectedProjects.length; i++) { + if (!isProjectInWorkspace(selectedProjects[i].getProjectName())) { + validProjects.add(selectedProjects[i]); + } + } + return (ProjectRecord[]) validProjects + .toArray(new ProjectRecord[validProjects.size()]); + } + + /** + * Determine if the project with the given name is in the current workspace. + * + * @param projectName + * String the project name to check + * @return boolean true if the project with the given name is in this + * workspace + */ + private boolean isProjectInWorkspace(String projectName) { + if (projectName == null) { + return false; + } + IProject[] workspaceProjects = getProjectsInWorkspace(); + for (int i = 0; i < workspaceProjects.length; i++) { + if (projectName.equals(workspaceProjects[i].getName())) { + return true; + } + } + return false; + } + +} diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RepositorySelectionPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RepositorySelectionPage.java index 86cf6ec..4f02c95 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RepositorySelectionPage.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RepositorySelectionPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@xxxxxxxxxx> + * Copyright (C) 2007, 2008, Robin Rosenberg <robin.rosenberg@xxxxxxxxxx> * Copyright (C) 2008, Roger C. Soares <rogersoares@xxxxxxxxxxxxxxxx> * Copyright (C) 2008, Shawn O. Pearce <spearce@xxxxxxxxxxx> * Copyright (C) 2008, Marek Zawirski <marek.zawirski@xxxxxxxxx> @@ -660,4 +660,11 @@ private void updateAuthGroup() { break; } } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) + uriText.setFocus(); + } } diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties index 22e29c2..98ce80f 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties @@ -15,6 +15,21 @@ ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 ## +WizardProjectsImportPage_projectLabel={0} ({1}) +WizardProjectsImportPage_ImportProjectsTitle=Import Projects +WizardProjectsImportPage_ImportProjectsDescription=Import projects from cloned repository into workbench +WizardProjectsImportPage_ProjectsListTitle=&Projects +WizardProjectsImportPage_selectAll = &Select All +WizardProjectsImportPage_deselectAll = &Deselect All +WizardProjectsImportPage_SearchingMessage = Searching for projects +WizardProjectsImportPage_ProcessingMessage = Processing results +WizardProjectsImportPage_projectsInWorkspace = Some projects were hidden because they exist in the workspace directory +WizardProjectsImportPage_CheckingMessage = Checking: {0} +WizardProjectsImportPage_SelectDialogTitle = Select root directory of the projects to import +WizardProjectImportPage_errorMessage = Creation Problems +WizardProjectsImportPage_CreateProjectsTask = Creating Projects +WizardProjectsImportPage_enableGit = Enable Git Team operations on imported projects + SharingWizard_windowTitle=Configure Git Repository SharingWizard_failed=Failed to initialize Git team provider. -- 1.6.1.rc3.56.gd0306 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html