Java tutorial
/******************************************************************************* * Copyright (c) 2004, 2008 IBM Corporation and others. * Copyright (C) 2007, Martin Oberhuber (martin.oberhuber@windriver.com) * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2009, Mykola Nikishov <mn@mn.com.ua> * Copyright (C) 2010, Wim Jongman <wim.jongman@remainsoftware.com> * Copyright (C) 2010, Ryan Schmitt <ryan.schmitt@boeing.com> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.egit.ui.internal.clone; 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.IWorkspaceRoot; 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.egit.ui.Activator; import org.eclipse.egit.ui.UIText; import org.eclipse.egit.ui.internal.CachedCheckboxTreeViewer; import org.eclipse.egit.ui.internal.FilteredCheckboxTree; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.IColorProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TreeViewer; 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.graphics.Color; 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.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.IWorkingSetManager; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.dialogs.PatternFilter; import org.eclipse.ui.dialogs.WorkingSetGroup; import org.eclipse.ui.statushandlers.StatusManager; /** * The GitWizardProjectsImportPage is the page that allows the user to import * projects from a particular location. This is a modified copy of the * WizardProjectsImportPage class from the org.eclipse.ui.ide bundle. */ public class GitProjectsImportPage extends WizardPage { private final class ProjectLabelProvider extends LabelProvider implements IColorProvider { public String getText(Object element) { return ((ProjectRecord) element).getProjectLabel(); } public Color getForeground(Object element) { if (isProjectInWorkspace(((ProjectRecord) element).getProjectName())) return PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_GRAY); return null; } public Color getBackground(Object element) { return null; } } /** * The name of the folder containing metadata information for the workspace. */ public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$ private CachedCheckboxTreeViewer 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 minimize searches private long lastModified; private Button selectAll; private Button deselectAll; private WorkingSetGroup workingSetGroup; /** * Creates a new project creation wizard page. */ public GitProjectsImportPage() { super(GitProjectsImportPage.class.getName()); setPageComplete(false); setTitle(UIText.WizardProjectsImportPage_ImportProjectsTitle); setDescription(UIText.WizardProjectsImportPage_ImportProjectsDescription); } 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); createWorkingSetGroup(workArea); Dialog.applyDialogFont(workArea); } private void createWorkingSetGroup(Composite workArea) { // TODO: replace hardcoded ids once bug 245106 is fixed String[] workingSetTypes = new String[] { "org.eclipse.ui.resourceWorkingSetPage", //$NON-NLS-1$ "org.eclipse.jdt.ui.JavaWorkingSetPage" //$NON-NLS-1$ }; workingSetGroup = new WorkingSetGroup(workArea, null, workingSetTypes); } /** * 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)); PatternFilter filter = new PatternFilter() { @Override public boolean isElementVisible(Viewer viewer, Object element) { if (getCheckedProjects().contains(element)) return true; return super.isElementVisible(viewer, element); } }; FilteredCheckboxTree filteredTree = new FilteredCheckboxTree(listComposite, null, SWT.NONE, filter); filteredTree.setInitialText(UIText.WizardProjectsImportPage_filterText); projectsList = filteredTree.getCheckboxTreeViewer(); GridData listData = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_BOTH); projectsList.getControl().setLayoutData(listData); projectsList.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(CheckStateChangedEvent event) { ProjectRecord element = (ProjectRecord) event.getElement(); if (isProjectInWorkspace(element.getProjectName())) { projectsList.setChecked(element, false); } enableSelectAllButtons(); } }); // a bug in the CachedCheckboxTreeView requires us to not return null final Object[] children = new Object[0]; projectsList.setContentProvider(new ITreeContentProvider() { public Object[] getChildren(Object parentElement) { return children; } public Object[] getElements(Object inputElement) { return selectedProjects; } public boolean hasChildren(Object element) { return false; } public Object getParent(Object element) { return null; } public void dispose() { // ignore } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // ignore } }); projectsList.getTree().addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { checkPageComplete(); } }); projectsList.setLabelProvider(new ProjectLabelProvider()); 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)); selectAll = new Button(buttonsComposite, SWT.PUSH); selectAll.setText(UIText.WizardProjectsImportPage_selectAll); selectAll.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { for (TreeItem item : projectsList.getTree().getItems()) { ProjectRecord record = (ProjectRecord) item.getData(); if (!isProjectInWorkspace(record.getProjectName())) projectsList.setChecked(item.getData(), true); } enableSelectAllButtons(); setPageComplete(true); } }); Dialog.applyDialogFont(selectAll); setButtonLayoutData(selectAll); deselectAll = new Button(buttonsComposite, SWT.PUSH); deselectAll.setText(UIText.WizardProjectsImportPage_deselectAll); deselectAll.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { for (TreeItem item : projectsList.getTree().getItems()) projectsList.setChecked(item.getData(), false); projectsList.setInput(this); // filter away selected projects enableSelectAllButtons(); 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)); } /** * Update the list of projects based on path. This will not check any * projects. * * @param path */ void setProjectsList(final String path) { // on an empty path empty selectedProjects if (path == null || path.length() == 0) { selectedProjects = new ProjectRecord[0]; projectsList.refresh(true); checkPageComplete(); lastPath = path; setErrorMessage(UIText.GitProjectsImportPage_NoProjectsMessage); 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; } setErrorMessage(null); lastPath = path; lastModified = modified; try { getContainer().run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { monitor.beginTask(UIText.WizardProjectsImportPage_SearchingMessage, 100); selectedProjects = new ProjectRecord[0]; Collection<File> files = new ArrayList<File>(); monitor.worked(10); if (directory.isDirectory()) { if (!collectProjectFilesFromDirectory(files, directory, null, monitor)) { return; } Iterator<File> filesIterator = files.iterator(); selectedProjects = new ProjectRecord[files.size()]; int index = 0; monitor.worked(50); monitor.subTask(UIText.WizardProjectsImportPage_ProcessingMessage); while (filesIterator.hasNext()) { File file = filesIterator.next(); selectedProjects[index] = new ProjectRecord(file); index++; } if (files.isEmpty()) // run in UI thread Display.getDefault().syncExec(new Runnable() { public void run() { setErrorMessage(UIText.GitProjectsImportPage_NoProjectsMessage); } }); } else { monitor.worked(60); } monitor.done(); } }); } catch (InvocationTargetException e) { Activator.logError(e.getMessage(), e); } catch (InterruptedException e) { // Nothing to do if the user interrupts. } projectsList.refresh(true); if (getValidProjects().length < selectedProjects.length) { setMessage(UIText.WizardProjectsImportPage_projectsInWorkspace, WARNING); } else { setMessage(UIText.WizardProjectsImportPage_ImportProjectsDescription); } enableSelectAllButtons(); checkPageComplete(); } private void enableSelectAllButtons() { int itemCount = getValidProjects().length; int selectionCount = projectsList.getCheckedLeafCount(); selectAll.setEnabled(itemCount > selectionCount && itemCount > 0); deselectAll.setEnabled(selectionCount > 0); } /** * Collect the list of .project files that are under directory into files. * * @param files * @param directory * @param visistedDirs * 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<File> files, File directory, Set<String> visistedDirs, IProgressMonitor monitor) { Set<String> directoriesVisited; 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 (visistedDirs == null) { directoriesVisited = new HashSet<String>(); try { directoriesVisited.add(directory.getCanonicalPath()); } catch (IOException exception) { StatusManager.getManager().handle(new Status(IStatus.ERROR, Activator.getPluginId(), exception.getLocalizedMessage(), exception)); } } else { directoriesVisited = visistedDirs; } // 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(new Status(IStatus.ERROR, Activator.getPluginId(), 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 Set<ProjectRecord> selected = getCheckedProjects(); WorkspaceModifyOperation op = new WorkspaceModifyOperation() { protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { monitor.beginTask("", selected.size()); //$NON-NLS-1$ if (monitor.isCanceled()) { throw new OperationCanceledException(); } for (ProjectRecord projectRecord : selected) { createExistingProject(projectRecord, 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(); Activator.handleError(UIText.WizardProjectImportPage_errorMessage, t, true); return false; } addProjectsToWorkingSet(selected); return true; } private void addProjectsToWorkingSet(Set<ProjectRecord> selected) { IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); for (ProjectRecord projectRecord : selected) { IWorkingSet[] selectedWorkingSets = workingSetGroup.getSelectedWorkingSets(); String projectName = projectRecord.getProjectName(); IProject project = root.getProject(projectName); workingSetManager.addToWorkingSets(project, selectedWorkingSets); } } /** * 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)); project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 50)); } 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 TreeViewer 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 = ResourcesPlugin.getWorkspace().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<ProjectRecord> validProjects = new ArrayList<ProjectRecord>(); for (int i = 0; i < selectedProjects.length; i++) { if (!isProjectInWorkspace(selectedProjects[i].getProjectName())) { validProjects.add(selectedProjects[i]); } } return 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; } /** * @return All the currently checked projects in the projectsList tree */ private Set<ProjectRecord> getCheckedProjects() { HashSet<ProjectRecord> ret = new HashSet<ProjectRecord>(); for (Object selected : projectsList.getCheckedElements()) ret.add((ProjectRecord) selected); return ret; } private void checkPageComplete() { setPageComplete(!getCheckedProjects().isEmpty()); } }