Java tutorial
/******************************************************************************* * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> * Copyright (C) 2007, Jing Xue <jingxue@digizenstudio.com> * Copyright (C) 2007, Robin Rosenberg <me@lathund.dewire.com> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> * Copyright (C) 2011, Jens Baumgart <jens.baumgart@sap.com> * Copyright (C) 2012, Robin Stocker <robin@nibor.org> * * 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.commit; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.egit.core.EclipseGitProgressTransformer; import org.eclipse.egit.core.IteratorService; import org.eclipse.egit.core.op.CommitOperation; import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIUtils; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.dialogs.BasicConfigurationDialog; import org.eclipse.egit.ui.internal.dialogs.CommitDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.IndexDiff; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; /** * UI component for performing a commit */ public class CommitUI { private IndexDiff indexDiff; private Set<String> notIndexed; private Set<String> indexChanges; private Set<String> notTracked; private Set<String> files; private boolean amending; private Shell shell; private Repository repo; private IResource[] selectedResources; private boolean preselectAll; /** * Constructs a CommitUI object * @param shell * Shell to use for UI interaction. Must not be null. * @param repo * Repository to commit. Must not be null * @param selectedResources * Resources selected by the user. A file is preselected in the * commit dialog if the file is contained in selectedResources or * if selectedResources contains a resource that is parent of the * file. selectedResources must not be null. * @param preselectAll * preselect all changed files in the commit dialog. * If set to true selectedResources are ignored. */ public CommitUI(Shell shell, Repository repo, IResource[] selectedResources, boolean preselectAll) { this.shell = shell; this.repo = repo; this.selectedResources = new IResource[selectedResources.length]; // keep our own copy System.arraycopy(selectedResources, 0, this.selectedResources, 0, selectedResources.length); this.preselectAll = preselectAll; } /**1 * Performs a commit * @return true if a commit operation was triggered */ public boolean commit() { // let's see if there is any dirty editor around and // ask the user if they want to save or abort if (!UIUtils.saveAllEditors(repo)) return false; BasicConfigurationDialog.show(new Repository[] { repo }); resetState(); final IProject[] projects = getProjectsOfRepositories(); try { PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { buildIndexHeadDiffList(projects, monitor); } catch (IOException e) { throw new InvocationTargetException(e); } } }); } catch (InvocationTargetException e) { Activator.handleError(UIText.CommitAction_errorComputingDiffs, e.getCause(), true); return false; } catch (InterruptedException e) { return false; } CommitHelper commitHelper = new CommitHelper(repo); if (!commitHelper.canCommit()) { MessageDialog.openError(shell, UIText.CommitAction_cannotCommit, commitHelper.getCannotCommitMessage()); return false; } boolean amendAllowed = commitHelper.amendAllowed(); if (files.isEmpty()) { if (amendAllowed && commitHelper.getPreviousCommit() != null) { boolean result = MessageDialog.openQuestion(shell, UIText.CommitAction_noFilesToCommit, UIText.CommitAction_amendCommit); if (!result) return false; amending = true; } else { MessageDialog.openWarning(shell, UIText.CommitAction_noFilesToCommit, UIText.CommitAction_amendNotPossible); return false; } } CommitDialog commitDialog = new CommitDialog(shell); commitDialog.setAmending(amending); commitDialog.setAmendAllowed(amendAllowed); commitDialog.setFiles(repo, files, indexDiff); commitDialog.setPreselectedFiles(getSelectedFiles()); commitDialog.setPreselectAll(preselectAll); commitDialog.setAuthor(commitHelper.getAuthor()); commitDialog.setCommitter(commitHelper.getCommitter()); commitDialog .setAllowToChangeSelection(!commitHelper.isMergedResolved && !commitHelper.isCherryPickResolved); commitDialog.setCommitMessage(commitHelper.getCommitMessage()); if (commitDialog.open() != IDialogConstants.OK_ID) return false; final CommitOperation commitOperation; try { commitOperation = new CommitOperation(repo, commitDialog.getSelectedFiles(), notTracked, commitDialog.getAuthor(), commitDialog.getCommitter(), commitDialog.getCommitMessage()); } catch (CoreException e1) { Activator.handleError(UIText.CommitUI_commitFailed, e1, true); return false; } if (commitDialog.isAmending()) commitOperation.setAmending(true); commitOperation.setComputeChangeId(commitDialog.getCreateChangeId()); commitOperation.setCommitAll(commitHelper.isMergedResolved); if (commitHelper.isMergedResolved) commitOperation.setRepository(repo); Job commitJob = new CommitJob(repo, commitOperation).setPushUpstream(commitDialog.isPushRequested()); commitJob.schedule(); return true; } private IProject[] getProjectsOfRepositories() { Set<IProject> ret = new HashSet<IProject>(); final IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject project : projects) { RepositoryMapping mapping = RepositoryMapping.getMapping(project); if (mapping != null && mapping.getRepository() == repo) ret.add(project); } return ret.toArray(new IProject[ret.size()]); } private void resetState() { files = new LinkedHashSet<String>(); notIndexed = new LinkedHashSet<String>(); indexChanges = new LinkedHashSet<String>(); notTracked = new LinkedHashSet<String>(); amending = false; indexDiff = null; } /** * Retrieves a collection of files that may be committed based on the user's * selection when they performed the commit action. That is, even if the * user only selected one folder when the action was performed, if the * folder contains any files that could be committed, they will be returned. * * @return a collection of files that is eligible to be committed based on * the user's selection */ private Set<String> getSelectedFiles() { Set<String> preselectionCandidates = new LinkedHashSet<String>(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); // iterate through all the files that may be committed for (String fileName : files) { URI uri = new File(repo.getWorkTree(), fileName).toURI(); IFile[] workspaceFiles = root.findFilesForLocationURI(uri); if (workspaceFiles.length > 0) { IFile file = workspaceFiles[0]; for (IResource resource : selectedResources) { // if any selected resource contains the file, add it as a // preselection candidate if (resource.contains(file)) { preselectionCandidates.add(fileName); break; } } } else { // could be file outside of workspace for (IResource resource : selectedResources) { if (resource.getFullPath().toFile().equals(new File(uri))) { preselectionCandidates.add(fileName); } } } } return preselectionCandidates; } private void buildIndexHeadDiffList(IProject[] selectedProjects, IProgressMonitor monitor) throws IOException, OperationCanceledException { monitor.beginTask(UIText.CommitActionHandler_calculatingChanges, 1000); EclipseGitProgressTransformer jgitMonitor = new EclipseGitProgressTransformer(monitor); CountingVisitor counter = new CountingVisitor(); for (IProject p : selectedProjects) { try { p.accept(counter); } catch (CoreException e) { // ignore } } WorkingTreeIterator it = IteratorService.createInitialIterator(repo); if (it == null) throw new OperationCanceledException(); // workspace is closed indexDiff = new IndexDiff(repo, Constants.HEAD, it); indexDiff.diff(jgitMonitor, counter.count, 0, NLS.bind(UIText.CommitActionHandler_repository, repo.getDirectory().getPath())); includeList(indexDiff.getAdded(), indexChanges); includeList(indexDiff.getChanged(), indexChanges); includeList(indexDiff.getRemoved(), indexChanges); includeList(indexDiff.getMissing(), notIndexed); includeList(indexDiff.getModified(), notIndexed); includeList(indexDiff.getUntracked(), notTracked); if (monitor.isCanceled()) throw new OperationCanceledException(); monitor.done(); } static class CountingVisitor implements IResourceVisitor { int count; public boolean visit(IResource resource) throws CoreException { count++; return true; } } private void includeList(Set<String> added, Set<String> category) { for (String filename : added) { if (!files.contains(filename)) files.add(filename); category.add(filename); } } }