/*******************************************************************************
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2011-2012, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2011-2012, Matthias Sohn <matthias.sohn@sap.com>
* Copyright (C) 2012-2013, Robin Stocker <robin@nibor.org>
* Copyright (C) 2012, Daniel Megert <daniel_megert@ch.ibm.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.history;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.IParameter;
import org.eclipse.core.commands.Parameterization;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.egit.core.op.CreatePatchOperation;
import org.eclipse.egit.core.op.CreatePatchOperation.DiffHeaderFormat;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.UIUtils;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.GitLabels;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.actions.ResetMenu;
import org.eclipse.egit.ui.internal.history.SWTCommitList.SWTLane;
import org.eclipse.egit.ui.internal.history.command.HistoryViewCommands;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.text.AbstractHoverInformationControlManager;
import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revplot.PlotCommit;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.part.IPageSite;
class CommitGraphTable {
static Font highlightFont() {
final Font n, h;
n = UIUtils.getFont(UIPreferences.THEME_CommitGraphNormalFont);
h = UIUtils.getFont(UIPreferences.THEME_CommitGraphHighlightFont);
final FontData[] nData = n.getFontData();
final FontData[] hData = h.getFontData();
if (nData.length != hData.length)
return h;
for (int i = 0; i < nData.length; i++)
if (!nData[i].equals(hData[i]))
return h;
return UIUtils.getBoldFont(UIPreferences.THEME_CommitGraphNormalFont);
}
private static final String LINESEP = System.getProperty("line.separator"); //$NON-NLS-1$
private final TableViewer table;
private Clipboard clipboard;
private final SWTPlotRenderer renderer;
private final Font nFont;
private final Font hFont;
private SWTCommitList allCommits;
private int allCommitsLength = 0;
// used for resolving PlotCommit objects by ids
private HashMap<String, PlotCommit> commitsMap = null;
private RevFlag highlight;
private HistoryPageInput input;
IAction copy;
MenuListener menuListener;
private RevCommit commitToShow;
private GraphLabelProvider graphLabelProvider;
private final TableLoader tableLoader;
private boolean trace = GitTraceLocation.HISTORYVIEW.isActive();
CommitGraphTable(Composite parent, final TableLoader loader,
final ResourceManager resources) {
nFont = UIUtils.getFont(UIPreferences.THEME_CommitGraphNormalFont);
hFont = highlightFont();
tableLoader = loader;
final Table rawTable = new Table(parent, SWT.MULTI | SWT.H_SCROLL
| SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
rawTable.setHeaderVisible(true);
rawTable.setLinesVisible(false);
rawTable.setFont(nFont);
rawTable.addListener(SWT.SetData, new Listener() {
public void handleEvent(Event event) {
if (tableLoader != null) {
TableItem item = (TableItem) event.item;
int index = rawTable.indexOf(item);
if (trace)
GitTraceLocation.getTrace().trace(
GitTraceLocation.HISTORYVIEW.getLocation(),
"Item " + index); //$NON-NLS-1$
tableLoader.loadItem(index);
}
}
});
final TableLayout layout = new TableLayout();
rawTable.setLayout(layout);
createColumns(rawTable, layout);
createPaintListener(rawTable);
table = new TableViewer(rawTable) {
protected Widget doFindItem(final Object element) {
return element != null ? ((SWTCommit) element).widget : null;
}
protected void mapElement(final Object element, final Widget item) {
((SWTCommit) element).widget = item;
}
};
graphLabelProvider = new GraphLabelProvider();
table.setLabelProvider(graphLabelProvider);
table.setContentProvider(new GraphContentProvider());
renderer = new SWTPlotRenderer(rawTable.getDisplay(), resources);
clipboard = new Clipboard(rawTable.getDisplay());
rawTable.addDisposeListener(new DisposeListener() {
public void widgetDisposed(final DisposeEvent e) {
clipboard.dispose();
}
});
copy = createStandardAction(ActionFactory.COPY);
table.setUseHashlookup(true);
table.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
ISelection s = event.getSelection();
if (s.isEmpty() || !(s instanceof IStructuredSelection))
return;
final IStructuredSelection iss = (IStructuredSelection) s;
commitToShow = (PlotCommit<?>) iss.getFirstElement();
copy.setEnabled(canDoCopy());
}
});
final RefHoverInformationControlManager hoverManager = new RefHoverInformationControlManager();
hoverManager.install(table.getTable());
table.getTable().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (allCommits != null)
allCommits.dispose();
hoverManager.dispose();
}
});
Transfer[] transferTypes = new Transfer[] {TextTransfer.getInstance(), FileTransfer.getInstance()};
table.addDragSupport(DND.DROP_DEFAULT | DND.DROP_COPY, transferTypes,
new CommitDragSourceListener());
}
CommitGraphTable(final Composite parent, final IPageSite site,
final MenuManager menuMgr, final TableLoader loader,
final ResourceManager resources) {
this(parent, loader, resources);
final IAction selectAll = createStandardAction(ActionFactory.SELECT_ALL);
getControl().addFocusListener(new FocusListener() {
public void focusLost(FocusEvent e) {
site.getActionBars().setGlobalActionHandler(
ActionFactory.SELECT_ALL.getId(), null);
site.getActionBars().setGlobalActionHandler(
ActionFactory.COPY.getId(), null);
site.getActionBars().updateActionBars();
}
public void focusGained(FocusEvent e) {
site.getActionBars().setGlobalActionHandler(
ActionFactory.SELECT_ALL.getId(), selectAll);
site.getActionBars().setGlobalActionHandler(
ActionFactory.COPY.getId(), copy);
site.getActionBars().updateActionBars();
}
});
getTableView().addOpenListener(new IOpenListener() {
public void open(OpenEvent event) {
if (input == null || !input.isSingleFile())
return;
ICommandService srv = CommonUtils.getService(site, ICommandService.class);
IHandlerService hsrv = CommonUtils.getService(site, IHandlerService.class);
Command cmd = srv.getCommand(HistoryViewCommands.SHOWVERSIONS);
Parameterization[] parms;
if (Activator.getDefault().getPreferenceStore().getBoolean(
UIPreferences.RESOURCEHISTORY_COMPARE_MODE))
try {
IParameter parm = cmd
.getParameter(HistoryViewCommands.COMPARE_MODE_PARAM);
parms = new Parameterization[] { new Parameterization(
parm, Boolean.TRUE.toString()) };
} catch (NotDefinedException e) {
Activator.handleError(e.getMessage(), e, true);
parms = null;
}
else
parms = null;
ParameterizedCommand pcmd = new ParameterizedCommand(cmd, parms);
try {
hsrv.executeCommandInContext(pcmd, null, hsrv
.getCurrentState());
} catch (Exception e) {
Activator.handleError(e.getMessage(), e, true);
}
}
});
Control c = getControl();
menuMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
c.setMenu(menuMgr.createContextMenu(c));
c.addMenuDetectListener(menuListener = new MenuListener(menuMgr,
getTableView(), site, copy));
}
Control getControl() {
return table.getControl();
}
void selectCommitStored(final RevCommit c) {
commitToShow = c;
selectCommit(c);
}
void selectCommit(final RevCommit c) {
if (c instanceof PlotCommit)
table.setSelection(new StructuredSelection(c), true);
else if (commitsMap != null) {
PlotCommit swtCommit = commitsMap.get(c.getId().name());
if (swtCommit == null && tableLoader != null)
tableLoader.loadCommit(c);
if (swtCommit != null)
table.setSelection(new StructuredSelection(swtCommit), true);
}
}
void addSelectionChangedListener(final ISelectionChangedListener l) {
table.addPostSelectionChangedListener(l);
}
void removeSelectionChangedListener(final ISelectionChangedListener l) {
table.removePostSelectionChangedListener(l);
}
void setRelativeDate(boolean booleanValue) {
graphLabelProvider.setRelativeDate(booleanValue);
}
void setShowEmailAddresses(boolean booleanValue) {
graphLabelProvider.setShowEmailAddresses(booleanValue);
}
private boolean canDoCopy() {
return !table.getSelection().isEmpty();
}
private void doCopy() {
final ISelection s = table.getSelection();
if (s.isEmpty() || !(s instanceof IStructuredSelection))
return;
final IStructuredSelection iss = (IStructuredSelection) s;
final Iterator<PlotCommit> itr = iss.iterator();
final StringBuilder r = new StringBuilder();
while (itr.hasNext()) {
final PlotCommit d = itr.next();
if (r.length() > 0)
r.append(LINESEP);
r.append(d.getId().name());
}
if (clipboard == null || clipboard.isDisposed())
return;
clipboard.setContents(new Object[] { r.toString() },
new Transfer[] { TextTransfer.getInstance() }, DND.CLIPBOARD);
}
void setInput(final RevFlag hFlag, final SWTCommitList list,
final SWTCommit[] asArray, HistoryPageInput input, boolean keepPosition) {
int topIndex = -1;
if (keepPosition)
topIndex = table.getTable().getTopIndex();
setHistoryPageInput(input);
final SWTCommitList oldList = allCommits;
if (oldList != null && oldList != list)
oldList.dispose();
highlight = hFlag;
allCommits = list;
int newAllCommitsLength = allCommits.size();
table.setInput(asArray);
if (asArray != null && asArray.length > 0) {
if (oldList != list || allCommitsLength < newAllCommitsLength)
initCommitsMap();
} else
table.getTable().deselectAll();
allCommitsLength = newAllCommitsLength;
if (commitToShow != null)
selectCommit(commitToShow);
if (keepPosition)
table.getTable().setTopIndex(topIndex);
}
void setHistoryPageInput(HistoryPageInput input) {
this.input = input;
if (menuListener != null)
menuListener.setInput(input);
}
private void initCommitsMap() {
commitsMap = new HashMap<String, PlotCommit>();
// ensure that filling (GenerateHistoryJob) and reading (here)
// the commit list is thread safe
synchronized (allCommits) {
for (PlotCommit commit : allCommits)
if (commit != null)
commitsMap.put(commit.getId().name(), commit);
}
}
private void createColumns(final Table rawTable, final TableLayout layout) {
final TableColumn commitId = new TableColumn(rawTable, SWT.NONE);
commitId.setResizable(true);
commitId.setText(UIText.CommitGraphTable_CommitId);
int minWidth;
GC gc = new GC(rawTable.getDisplay());
try {
gc.setFont(rawTable.getFont());
minWidth = gc.stringExtent("0000000").x + 5; //$NON-NLS-1$
} finally {
gc.dispose();
}
layout.addColumnData(new ColumnWeightData(1, minWidth, true));
final TableColumn graph = new TableColumn(rawTable, SWT.NONE);
graph.setResizable(true);
graph.setText(UIText.CommitGraphTable_messageColumn);
graph.setWidth(400);
layout.addColumnData(new ColumnWeightData(20, true));
final TableColumn author = new TableColumn(rawTable, SWT.NONE);
author.setResizable(true);
author.setText(UIText.HistoryPage_authorColumn);
author.setWidth(100);
layout.addColumnData(new ColumnWeightData(5, true));
final TableColumn date = new TableColumn(rawTable, SWT.NONE);
date.setResizable(true);
date.setText(UIText.HistoryPage_authorDateColumn);
date.setWidth(100);
layout.addColumnData(new ColumnWeightData(5, true));
final TableColumn committer = new TableColumn(rawTable, SWT.NONE);
committer.setResizable(true);
committer.setText(UIText.CommitGraphTable_Committer);
committer.setWidth(100);
layout.addColumnData(new ColumnWeightData(5, true));
final TableColumn committerDate = new TableColumn(rawTable, SWT.NONE);
committerDate.setResizable(true);
committerDate.setText(UIText.CommitGraphTable_committerDataColumn);
committerDate.setWidth(100);
layout.addColumnData(new ColumnWeightData(5, true));
}
private void createPaintListener(final Table rawTable) {
// Tell SWT we will completely handle painting for some columns.
//
rawTable.addListener(SWT.EraseItem, new Listener() {
public void handleEvent(final Event event) {
if (0 <= event.index && event.index <= 5)
event.detail &= ~SWT.FOREGROUND;
}
});
rawTable.addListener(SWT.PaintItem, new Listener() {
public void handleEvent(final Event event) {
doPaint(event);
}
});
}
void doPaint(final Event event) {
final RevCommit c = (RevCommit) ((TableItem) event.item).getData();
if (c instanceof SWTCommit) {
final SWTLane lane = ((SWTCommit) c).getLane();
if (lane != null && lane.color.isDisposed())
return;
}
if (highlight != null && c.has(highlight))
event.gc.setFont(hFont);
else
event.gc.setFont(nFont);
if (event.index == 1) {
renderer.paint(event, input == null ? null : input.getHead());
return;
}
final ITableLabelProvider lbl;
final String txt;
lbl = (ITableLabelProvider) table.getLabelProvider();
txt = lbl.getColumnText(c, event.index);
final Point textsz = event.gc.textExtent(txt);
final int texty = (event.height - textsz.y) / 2;
event.gc.drawString(txt, event.x, event.y + texty, true);
}
/**
* Returns the SWT TableView of this CommitGraphTable.
*
* @return Table the SWT Table
*/
public TableViewer getTableView() {
return table;
}
private IAction createStandardAction(final ActionFactory af) {
final String text = af.create(
PlatformUI.getWorkbench().getActiveWorkbenchWindow()).getText();
IAction action = new Action() {
@Override
public String getActionDefinitionId() {
return af.getCommandId();
}
@Override
public String getId() {
return af.getId();
}
@Override
public String getText() {
return text;
}
@Override
public void run() {
if (af == ActionFactory.SELECT_ALL)
table.getTable().selectAll();
if (af == ActionFactory.COPY)
doCopy();
}
};
return action;
}
private static final class RefHoverInformationControlCreator extends
AbstractReusableInformationControlCreator {
@Override
protected IInformationControl doCreateInformationControl(Shell parent) {
return new DefaultInformationControl(parent);
}
}
private final class RefHoverInformationControlManager extends
AbstractHoverInformationControlManager {
protected RefHoverInformationControlManager() {
super(new RefHoverInformationControlCreator());
}
@Override
protected void computeInformation() {
MouseEvent e = getHoverEvent();
TableItem item = table.getTable().getItem(new Point(e.x, e.y));
if (item != null) {
SWTCommit commit = (SWTCommit) item.getData();
if (commit != null && commit.getRefCount() > 0) {
Rectangle itemBounds = item.getBounds();
int firstColumnWidth = table.getTable().getColumn(0).getWidth();
int relativeX = e.x - firstColumnWidth - itemBounds.x;
for (int i = 0; i < commit.getRefCount(); i++) {
Ref ref = commit.getRef(i);
Point textSpan = renderer.getRefHSpan(ref);
if ((textSpan != null)
&& (relativeX >= textSpan.x && relativeX <= textSpan.y)) {
String hoverText = getHoverText(ref, i, commit);
int width = textSpan.y - textSpan.x;
Rectangle rectangle = new Rectangle(
firstColumnWidth + itemBounds.x
+ textSpan.x, itemBounds.y, width,
itemBounds.height);
setInformation(hoverText, rectangle);
return;
}
}
}
}
// computeInformation must setInformation in all cases
setInformation(null, null);
}
private String getHoverText(Ref ref, int refIndex, SWTCommit commit) {
if (ref.getName().startsWith(Constants.R_TAGS)
&& renderer.isShownAsEllipsis(ref)) {
StringBuilder sb = new StringBuilder(UIText.CommitGraphTable_HoverAdditionalTags);
for (int i = refIndex; i < commit.getRefCount(); i++) {
Ref tag = commit.getRef(i);
String name = tag.getName();
if (name.startsWith(Constants.R_TAGS)) {
sb.append('\n');
sb.append(name.substring(Constants.R_TAGS.length()));
}
}
return sb.toString();
} else {
return getHoverTextForSingleRef(ref);
}
}
private String getHoverTextForSingleRef(Ref r) {
StringBuilder sb = new StringBuilder();
String name = r.getName();
sb.append(name);
if (r.isSymbolic()) {
sb.append(": "); //$NON-NLS-1$
sb.append(r.getLeaf().getName());
}
String description = GitLabels.getRefDescription(r);
if (description != null) {
sb.append("\n"); //$NON-NLS-1$
sb.append(description);
}
return sb.toString();
}
}
private final class CommitDragSourceListener extends DragSourceAdapter {
@Override
public void dragStart(DragSourceEvent event) {
RevCommit commit = getSelectedCommit();
event.doit = commit.getParentCount() == 1;
}
public void dragSetData(DragSourceEvent event) {
boolean isFileTransfer = FileTransfer.getInstance()
.isSupportedType(event.dataType);
boolean isTextTransfer = TextTransfer.getInstance()
.isSupportedType(event.dataType);
if (isFileTransfer || isTextTransfer) {
RevCommit commit = getSelectedCommit();
String patchContent = createPatch(commit);
if (isTextTransfer) {
event.data = patchContent;
return;
} else {
File patchFile = null;
try {
patchFile = createTempFile(commit);
writeToFile(patchFile.getAbsolutePath(), patchContent);
event.data = new String[] { patchFile.getAbsolutePath() };
} catch (IOException e) {
Activator.logError(NLS.bind(
UIText.CommitGraphTable_UnableToWritePatch,
commit.getId().name()), e);
} finally {
if (patchFile != null)
patchFile.deleteOnExit();
}
}
}
}
private File createTempFile(RevCommit commit) throws IOException {
String tmpDir = System.getProperty("java.io.tmpdir"); //$NON-NLS-1$
String patchName = "egit-patch" + commit.getId().name(); //$NON-NLS-1$
File patchDir = new File(tmpDir, patchName);
int counter = 1;
while(patchDir.exists()) {
patchDir = new File(tmpDir, patchName + "_" + counter); //$NON-NLS-1$
counter++;
}
FileUtils.mkdir(patchDir);
patchDir.deleteOnExit();
File patchFile;
String suggestedFileName = CreatePatchOperation
.suggestFileName(commit);
patchFile = new File(patchDir, suggestedFileName);
return patchFile;
}
private String createPatch(RevCommit commit) {
Repository repository = input.getRepository();
CreatePatchOperation operation = new CreatePatchOperation(
repository, commit);
operation.setHeaderFormat(DiffHeaderFormat.EMAIL);
operation.setContextLines(CreatePatchOperation.DEFAULT_CONTEXT_LINES);
try {
operation.execute(null);
} catch (CoreException e) {
Activator.logError(NLS.bind(
UIText.CommitGraphTable_UnableToCreatePatch, commit
.getId().name()), e);
}
String patchContent = operation.getPatchContent();
return patchContent;
}
private RevCommit getSelectedCommit() {
IStructuredSelection selection = (IStructuredSelection) table
.getSelection();
RevCommit commit = (RevCommit) selection.getFirstElement();
RevWalk walk = new org.eclipse.jgit.revwalk.RevWalk(input.getRepository());
try {
return walk.parseCommit(commit.getId());
} catch (IOException e) {
throw new RuntimeException(
"Could not parse commit " + commit.getId(), e); //$NON-NLS-1$
} finally {
walk.release();
}
}
private void writeToFile(final String fileName, String content)
throws IOException {
Writer output = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(fileName), RawParseUtils.UTF8_CHARSET));
try {
output.write(content);
} finally {
output.close();
}
}
}
private final static class MenuListener implements MenuDetectListener {
private final MenuManager popupMgr;
private final ISelectionProvider selectionProvider;
private final IPageSite site;
private final IAction copyAction;
private HistoryPageInput input;
MenuListener(MenuManager menuManager,
ISelectionProvider selectionProvider, IPageSite site,
IAction copyAction) {
this.popupMgr = menuManager;
this.selectionProvider = selectionProvider;
this.site = site;
this.copyAction = copyAction;
}
public void setInput(HistoryPageInput input) {
this.input = input;
}
public void menuDetected(MenuDetectEvent e) {
popupMgr.removeAll();
int selectionSize = ((IStructuredSelection) selectionProvider
.getSelection()).size();
if (input.isSingleFile()) {
if (selectionSize == 1)
if (input.getSingleFile() instanceof IResource)
popupMgr
.add(getCommandContributionItem(
HistoryViewCommands.COMPARE_WITH_TREE,
UIText.GitHistoryPage_CompareWithWorkingTreeMenuMenuLabel));
else
popupMgr
.add(getCommandContributionItem(
HistoryViewCommands.COMPARE_WITH_TREE,
UIText.GitHistoryPage_CompareWithCurrentHeadMenu));
if (selectionSize > 0) {
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.OPEN,
UIText.GitHistoryPage_OpenMenuLabel));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.OPEN_IN_TEXT_EDITOR,
UIText.GitHistoryPage_OpenInTextEditorLabel));
}
if (selectionSize == 1)
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.SHOW_BLAME,
UIText.CommitFileDiffViewer_ShowAnnotationsMenuLabel));
}
if (selectionSize > 0) {
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.OPEN_IN_COMMIT_VIEWER,
UIText.CommitGraphTable_OpenCommitLabel));
}
if (selectionSize == 1) {
popupMgr.add(new Separator());
if (!input.getRepository().isBare()) {
if (hasMultipleRefNodes()) {
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.CHECKOUT,
UIText.GitHistoryPage_CheckoutMenuLabel2));
} else {
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.CHECKOUT,
UIText.GitHistoryPage_CheckoutMenuLabel));
}
}
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.PUSH_COMMIT,
UIText.GitHistoryPage_pushCommit));
popupMgr.add(new Separator());
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.CREATE_BRANCH,
UIText.GitHistoryPage_CreateBranchMenuLabel));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.DELETE_BRANCH,
UIText.CommitGraphTable_DeleteBranchAction));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.RENAME_BRANCH,
UIText.CommitGraphTable_RenameBranchMenuLabel));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.CREATE_TAG,
UIText.GitHistoryPage_CreateTagMenuLabel));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.DELETE_TAG,
UIText.CommitGraphTable_DeleteTagAction));
popupMgr.add(new Separator());
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.CREATE_PATCH,
UIText.GitHistoryPage_CreatePatchMenuLabel));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.MERGE,
UIText.GitHistoryPage_mergeMenuItem));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.REBASECURRENT,
UIText.GitHistoryPage_rebaseMenuItem));
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.REBASE_INTERACTIVE_CURRENT,
UIText.GitHistoryPage_rebaseInteractiveMenuItem));
popupMgr.add(new Separator());
MenuManager resetManager = ResetMenu.createMenu(site);
popupMgr.add(resetManager);
} else if (selectionSize == 2) {
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.COMPARE_VERSIONS,
UIText.GitHistoryPage_CompareWithEachOtherMenuLabel));
if (!input.isSingleFile())
popupMgr
.add(getCommandContributionItem(
HistoryViewCommands.COMPARE_VERSIONS_IN_TREE,
UIText.CommitGraphTable_CompareWithEachOtherInTreeMenuLabel));
}
popupMgr.add(new Separator());
popupMgr.add(getCommandContributionItem(
HistoryViewCommands.CHERRYPICK,
UIText.GitHistoryPage_cherryPickMenuItem));
popupMgr.add(getCommandContributionItem(HistoryViewCommands.REVERT,
UIText.GitHistoryPage_revertMenuItem));
popupMgr.add(new Separator());
MenuManager quickDiffManager = new MenuManager(
UIText.GitHistoryPage_QuickdiffMenuLabel, null, "Quickdiff"); //$NON-NLS-1$
popupMgr.add(quickDiffManager);
quickDiffManager.add(getCommandContributionItem(
HistoryViewCommands.SET_QUICKDIFF_BASELINE,
UIText.GitHistoryPage_SetAsBaselineMenuLabel));
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(HistoryViewCommands.BASELINE_TARGET, "HEAD"); //$NON-NLS-1$
quickDiffManager.add(getCommandContributionItem(
HistoryViewCommands.RESET_QUICKDIFF_BASELINE,
UIText.GitHistoryPage_ResetBaselineToHeadMenuLabel,
parameters));
parameters = new HashMap<String, String>();
parameters.put(HistoryViewCommands.BASELINE_TARGET, "HEAD^1"); //$NON-NLS-1$
quickDiffManager.add(getCommandContributionItem(
HistoryViewCommands.RESET_QUICKDIFF_BASELINE,
UIText.GitHistoryPage_ResetBaselineToParentOfHeadMenuLabel,
parameters));
popupMgr.add(new Separator());
MenuManager modifyManager = new MenuManager(
UIText.GitHistoryPage_ModifyMenuLabel, null, "Modify"); //$NON-NLS-1$
popupMgr.add(modifyManager);
if (selectionSize == 1) {
modifyManager.add(getCommandContributionItem(
HistoryViewCommands.REWORD,
UIText.GitHistoryPage_rewordMenuItem));
modifyManager.add(getCommandContributionItem(
HistoryViewCommands.EDIT,
UIText.GitHistoryPage_editMenuItem));
}
if (selectionSize >= 2)
modifyManager.add(getCommandContributionItem(
HistoryViewCommands.SQUASH,
UIText.GitHistoryPage_squashMenuItem));
// copy and such after additions
popupMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
popupMgr.add(copyAction);
popupMgr.add(new Separator());
}
private boolean hasMultipleRefNodes() {
try {
Map<String, Ref> branches = input.getRepository()
.getRefDatabase().getRefs(Constants.R_HEADS);
int count = 0;
for (Ref branch : branches.values()) {
if (branch.getLeaf().getObjectId()
.equals(((RevCommit) ((IStructuredSelection) selectionProvider
.getSelection()).getFirstElement()).getId()))
count++;
}
return (count > 1);
} catch (IOException e) {
// ignore here
}
return false;
}
private CommandContributionItem getCommandContributionItem(
String commandId, String menuLabel) {
CommandContributionItemParameter parameter = new CommandContributionItemParameter(
site, commandId, commandId,
CommandContributionItem.STYLE_PUSH);
parameter.label = menuLabel;
return new CommandContributionItem(parameter);
}
private CommandContributionItem getCommandContributionItem(
String commandId, String menuLabel,
Map<String, String> parameters) {
CommandContributionItemParameter parameter = new CommandContributionItemParameter(
site, commandId, commandId,
CommandContributionItem.STYLE_PUSH);
parameter.label = menuLabel;
parameter.parameters = parameters;
return new CommandContributionItem(parameter);
}
}
}