/******************************************************************************* * Copyright (C) 2014 Robin Stocker <robin@nibor.org> and others. * * 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.actions; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.eclipse.core.resources.WorkspaceJob; 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.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.egit.core.RevUtils; import org.eclipse.egit.core.RevUtils.ConflictCommits; import org.eclipse.egit.core.internal.Utils; import org.eclipse.egit.core.internal.util.ResourceUtil; import org.eclipse.egit.core.op.DiscardChangesOperation; import org.eclipse.egit.core.op.DiscardChangesOperation.Stage; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.internal.CommonUtils; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.selection.SelectionUtils; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.osgi.util.NLS; import org.eclipse.ui.actions.CompoundContributionItem; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.menus.IWorkbenchContribution; import org.eclipse.ui.services.IServiceLocator; /** * Menu for replacing one/multiple files with version from ours/theirs on * conflict. */ public class ReplaceWithOursTheirsMenu extends CompoundContributionItem implements IWorkbenchContribution { private IServiceLocator serviceLocator; @Override public void initialize(IServiceLocator locator) { serviceLocator = locator; } @Override protected IContributionItem[] getContributionItems() { List<IContributionItem> items = new ArrayList<>(); IHandlerService handlerService = CommonUtils.getService(serviceLocator, IHandlerService.class); IStructuredSelection selection = SelectionUtils .getSelection(handlerService.getCurrentState()); IPath[] locations = SelectionUtils.getSelectedLocations(selection); if (locations.length == 0) return new IContributionItem[0]; Map<Repository, Collection<String>> pathsByRepository = ResourceUtil .splitPathsByRepository(Arrays.asList(locations)); if (pathsByRepository.size() == 1) { Repository repository = pathsByRepository.keySet().iterator() .next(); Collection<String> paths = pathsByRepository.get(repository); if (paths.size() == 1) { String path = paths.iterator().next(); items.addAll(createSpecificOursTheirsItems(repository, path)); } else if (paths.size() > 1) { items.addAll(createUnspecificOursTheirsItems(Arrays .asList(locations))); } } return items.toArray(new IContributionItem[0]); } private static Collection<IContributionItem> createSpecificOursTheirsItems( Repository repository, String path) { Collection<IPath> paths = Collections.<IPath> singleton(new Path( new File(repository.getWorkTree(), path).getAbsolutePath())); List<IContributionItem> result = new ArrayList<>(); try { ConflictCommits conflictCommits = RevUtils.getConflictCommits( repository, path); RevCommit ourCommit = conflictCommits.getOurCommit(); RevCommit theirCommit = conflictCommits.getTheirCommit(); if (ourCommit != null) result.add(createOursItem( formatCommit( UIText.ReplaceWithOursTheirsMenu_OursWithCommitLabel, ourCommit), paths)); else result.add(createOursItem(UIText.ReplaceWithOursTheirsMenu_OursWithoutCommitLabel, paths)); if (theirCommit != null) result.add(createTheirsItem( formatCommit( UIText.ReplaceWithOursTheirsMenu_TheirsWithCommitLabel, theirCommit), paths)); else result.add(createTheirsItem( UIText.ReplaceWithOursTheirsMenu_TheirsWithoutCommitLabel, paths)); return result; } catch (IOException e) { Activator.logError( UIText.ReplaceWithOursTheirsMenu_CalculatingOursTheirsCommitsError, e); return createUnspecificOursTheirsItems(paths); } } private static Collection<IContributionItem> createUnspecificOursTheirsItems( Collection<IPath> paths) { List<IContributionItem> result = new ArrayList<>(); result.add(createOursItem( UIText.ReplaceWithOursTheirsMenu_OursWithoutCommitLabel, paths)); result.add(createTheirsItem( UIText.ReplaceWithOursTheirsMenu_TheirsWithoutCommitLabel, paths)); return result; } private static IContributionItem createOursItem(String label, final Collection<IPath> paths) { return new ActionContributionItem(new ReplaceAction(label, Stage.OURS, paths)); } private static IContributionItem createTheirsItem(String label, final Collection<IPath> paths) { return new ActionContributionItem(new ReplaceAction(label, Stage.THEIRS, paths)); } private static String formatCommit(String format, RevCommit commit) { String message = Utils.shortenText(commit.getShortMessage(), 60); return NLS.bind(format, commit.abbreviate(7).name(), message); } private static class ReplaceAction extends Action { private final Stage stage; private final Collection<IPath> paths; public ReplaceAction(String text, Stage stage, Collection<IPath> paths) { super(text); this.stage = stage; this.paths = paths; } @Override public void run() { final DiscardChangesOperation operation = new DiscardChangesOperation( paths); operation.setStage(stage); String jobname = UIText.DiscardChangesAction_discardChanges; Job job = new WorkspaceJob(jobname) { @Override public IStatus runInWorkspace(IProgressMonitor monitor) { try { operation.execute(monitor); } catch (CoreException e) { return Activator.createErrorStatus(e.getStatus() .getMessage(), e); } return Status.OK_STATUS; } @Override public boolean belongsTo(Object family) { if (JobFamilies.DISCARD_CHANGES.equals(family)) return true; return super.belongsTo(family); } }; job.setUser(true); job.setRule(operation.getSchedulingRule()); job.schedule(); } } }