Java tutorial
/******************************************************************************* * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> * Copyright (C) 2011, Dariusz Luksza <dariusz@luksza.org> * Copyright (C) 2012, Robin Stocker <robin@nibor.org> * Copyright (C) 2012, Franois Rey <eclipse.org_@_francois_._rey_._name> * * 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.bc; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.expressions.IEvaluationContext; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.resources.mapping.ResourceTraversal; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.egit.core.AdapterUtils; import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.egit.ui.UIText; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.RenameDetector; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.FollowFilter; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.ISources; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.handlers.HandlerUtil; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.ide.ResourceUtil; /** * A helper class for Team Actions on Git controlled projects */ public abstract class BeyondCompareRepositoryActionHandler extends AbstractHandler { private IEvaluationContext evaluationContext; private IStructuredSelection mySelection; /** * Set the selection when used by {@link RepositoryAction} as * {@link IWorkbenchWindowActionDelegate} * * @param selection * the new selection */ public void setSelection(ISelection selection) { mySelection = convertSelection(null, selection); } /** * @param projects * a list of projects * @return the repositories that projects map to iff all projects are mapped */ protected Repository[] getRepositoriesFor(final IProject[] projects) { Set<Repository> ret = new LinkedHashSet<Repository>(); for (IProject project : projects) { RepositoryMapping repositoryMapping = RepositoryMapping.getMapping(project); if (repositoryMapping == null) return new Repository[0]; ret.add(repositoryMapping.getRepository()); } return ret.toArray(new Repository[ret.size()]); } /** * Figure out which repository to use. All selected resources must map to * the same Git repository. * * @param warn * Put up a message dialog to warn why a resource was not * selected * @param event * @return repository for current project, or null * @throws ExecutionException */ protected Repository getRepository(boolean warn, ExecutionEvent event) throws ExecutionException { IStructuredSelection selection = getSelection(event); Shell shell = getShell(event); return getRepository(warn, selection, shell); } /** * Figure out which repository to use. All selected resources must map to * the same Git repository. * * @return repository for current project, or null */ protected Repository getRepository() { IStructuredSelection selection = getSelection(); return getRepository(false, selection, null); } /** * Figure out which repository to use. All selected resources must map to * the same Git repository. * * @param warn * Put up a message dialog to warn why a resource was not * selected * @param selection * @param shell * must be provided if warn = true * @return repository for current project, or null */ private Repository getRepository(boolean warn, IStructuredSelection selection, Shell shell) { RepositoryMapping mapping = null; for (IPath location : getSelectedLocations(selection)) { IResource resource = ResourceUtil2.getResourceForLocation(location); RepositoryMapping repositoryMapping = RepositoryMapping.getMapping(resource); if (mapping == null) mapping = repositoryMapping; if (repositoryMapping == null) return null; if (mapping.getRepository() != repositoryMapping.getRepository()) { if (warn) MessageDialog.openError(shell, UIText.RepositoryAction_multiRepoSelectionTitle, UIText.RepositoryAction_multiRepoSelection); return null; } } Repository result = null; if (mapping == null) for (Object o : selection.toArray()) { Repository nextRepo = null; if (o instanceof Repository) nextRepo = (Repository) o; else if (o instanceof PlatformObject) nextRepo = (Repository) ((PlatformObject) o).getAdapter(Repository.class); if (nextRepo != null && result != null && !result.equals(nextRepo)) { if (warn) MessageDialog.openError(shell, UIText.RepositoryAction_multiRepoSelectionTitle, UIText.RepositoryAction_multiRepoSelection); return null; } result = nextRepo; } else result = mapping.getRepository(); if (result == null) { if (warn) MessageDialog.openError(shell, UIText.RepositoryAction_errorFindingRepoTitle, UIText.RepositoryAction_errorFindingRepo); return null; } return result; } /** * @param event * the execution event, must not be null * @return the current selection * @throws ExecutionException * if the selection can't be determined */ protected IStructuredSelection getSelection(ExecutionEvent event) throws ExecutionException { if (event == null) throw new IllegalArgumentException("event must not be NULL"); //$NON-NLS-1$ Object selection = HandlerUtil.getActiveMenuSelection(event); if (selection == null) selection = HandlerUtil.getCurrentSelectionChecked(event); if (selection instanceof TextSelection) { IEditorInput editorInput = (IEditorInput) HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME); IResource resource = ResourceUtil.getResource(editorInput); if (resource != null) return new StructuredSelection(resource); resource = ResourceUtil.getFile(editorInput); if (resource != null) return new StructuredSelection(resource); } if (selection instanceof IStructuredSelection) return (IStructuredSelection) selection; return StructuredSelection.EMPTY; } /** * @return the current selection */ protected IStructuredSelection getSelection() { // if the selection was set explicitly, use it if (mySelection != null) return mySelection; return convertSelection(evaluationContext, null); } private IStructuredSelection convertSelection(IEvaluationContext aContext, Object aSelection) { IEvaluationContext ctx; if (aContext == null && aSelection == null) return StructuredSelection.EMPTY; else ctx = aContext; Object selection; if (aSelection == null && ctx != null) { selection = ctx.getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); if (!(selection instanceof ISelection)) selection = ctx.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME); } else if (aSelection != null) selection = aSelection; else return StructuredSelection.EMPTY; if (selection instanceof TextSelection) { if (ctx == null) ctx = getEvaluationContext(); IResource resource = ResourceUtil.getResource(ctx.getVariable(ISources.ACTIVE_EDITOR_INPUT_NAME)); if (resource != null) return new StructuredSelection(resource); } if (selection instanceof IStructuredSelection) return (IStructuredSelection) selection; return StructuredSelection.EMPTY; } public void setEnabled(Object evaluationContext) { this.evaluationContext = (IEvaluationContext) evaluationContext; } private IEvaluationContext getEvaluationContext() { IEvaluationContext ctx; IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); // no active window during Eclipse shutdown if (activeWorkbenchWindow == null) return null; IHandlerService hsr = (IHandlerService) activeWorkbenchWindow.getService(IHandlerService.class); ctx = hsr.getCurrentState(); return ctx; } /** * @param event * @return the resources in the selection * @throws ExecutionException */ protected IResource[] getSelectedResources(ExecutionEvent event) throws ExecutionException { IStructuredSelection selection = getSelection(event); return getSelectedResources(selection); } /** * @return the resources in the selection */ protected IResource[] getSelectedResources() { IStructuredSelection selection = getSelection(); return getSelectedResources(selection); } /** * @param selection * @return the resources in the selection */ private IResource[] getSelectedResources(IStructuredSelection selection) { Set<IResource> result = new LinkedHashSet<IResource>(); for (Object o : selection.toList()) { IResource resource = AdapterUtils.adapt(o, IResource.class); if (resource != null) result.add(resource); else result.addAll(extractResourcesFromMapping(o)); } return result.toArray(new IResource[result.size()]); } private IPath[] getSelectedLocations(IStructuredSelection selection) { Set<IPath> result = new LinkedHashSet<IPath>(); for (Object o : selection.toList()) { IResource resource = AdapterUtils.adapt(o, IResource.class); if (resource != null) { IPath location = resource.getLocation(); if (location != null) result.add(location); } else { IPath location = AdapterUtils.adapt(o, IPath.class); if (location != null) result.add(location); else for (IResource r : extractResourcesFromMapping(o)) { IPath l = r.getLocation(); if (l != null) result.add(l); } } } return result.toArray(new IPath[result.size()]); } private List<IResource> extractResourcesFromMapping(Object o) { ResourceMapping mapping = AdapterUtils.adapt(o, ResourceMapping.class); if (mapping != null) { ResourceTraversal[] traversals; try { traversals = mapping.getTraversals(null, null); for (ResourceTraversal traversal : traversals) { IResource[] resources = traversal.getResources(); return Arrays.asList(resources); } } catch (CoreException e) { Activator.logError(e.getMessage(), e); } } return Collections.emptyList(); } /** * @param event * @return the shell * @throws ExecutionException */ protected Shell getShell(ExecutionEvent event) throws ExecutionException { return HandlerUtil.getActiveShellChecked(event); } protected String getPreviousPath(Repository repository, ObjectReader reader, RevCommit headCommit, RevCommit previousCommit, String path) throws IOException { TreeWalk walk = new TreeWalk(reader); walk.setRecursive(true); walk.addTree(previousCommit.getTree()); walk.addTree(headCommit.getTree()); List<DiffEntry> entries = DiffEntry.scan(walk); if (entries.size() < 2) return path; for (DiffEntry diff : entries) if (diff.getChangeType() == ChangeType.MODIFY && path.equals(diff.getNewPath())) return path; RenameDetector detector = new RenameDetector(repository); detector.addAll(entries); List<DiffEntry> renames = detector.compute(walk.getObjectReader(), NullProgressMonitor.INSTANCE); for (DiffEntry diff : renames) if (diff.getChangeType() == ChangeType.RENAME && path.equals(diff.getNewPath())) return diff.getOldPath(); return path; } protected List<PreviousCommit> findPreviousCommits() throws IOException { List<PreviousCommit> result = new ArrayList<PreviousCommit>(); Repository repository = getRepository(); IResource resource = getSelectedResources()[0]; String path = RepositoryMapping.getMapping(resource.getProject()).getRepoRelativePath(resource); RevWalk rw = new RevWalk(repository); try { if (path.length() > 0) { FollowFilter filter = FollowFilter.create(path); rw.setTreeFilter(filter); } RevCommit headCommit = rw.parseCommit(repository.getRef(Constants.HEAD).getObjectId()); rw.markStart(headCommit); headCommit = rw.next(); if (headCommit == null) return result; List<RevCommit> directParents = Arrays.asList(headCommit.getParents()); RevCommit previousCommit = rw.next(); while (previousCommit != null && result.size() < directParents.size()) { if (directParents.contains(previousCommit)) { String previousPath = getPreviousPath(repository, rw.getObjectReader(), headCommit, previousCommit, path); result.add(new PreviousCommit(previousCommit, previousPath)); } previousCommit = rw.next(); } } finally { rw.dispose(); } return result; } // keep track of the path of an ancestor (for following renames) protected static final class PreviousCommit { final RevCommit commit; final String path; PreviousCommit(final RevCommit commit, final String path) { this.commit = commit; this.path = path; } } }