/*******************************************************************************
* Copyright (c) 2011, 2012 GitHub Inc. 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
*
* Contributors:
* Kevin Sawicki (GitHub Inc.) - initial API and implementation
* Daniel Megert <daniel_megert@ch.ibm.com> - Added context menu to the Commit Editor's header text
* Tomasz Zarna <Tomasz.Zarna@pl.ibm.com> - Add "Revert" action to Commit Editor
*******************************************************************************/
package org.eclipse.egit.ui.internal.commit;
import java.text.MessageFormat;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.commit.command.CheckoutHandler;
import org.eclipse.egit.ui.internal.commit.command.CherryPickHandler;
import org.eclipse.egit.ui.internal.commit.command.CreateBranchHandler;
import org.eclipse.egit.ui.internal.commit.command.CreateTagHandler;
import org.eclipse.egit.ui.internal.commit.command.RevertHandler;
import org.eclipse.egit.ui.internal.commit.command.ShowInHistoryHandler;
import org.eclipse.egit.ui.internal.commit.command.StashApplyHandler;
import org.eclipse.egit.ui.internal.commit.command.StashDropHandler;
import org.eclipse.egit.ui.internal.repository.RepositoriesView;
import org.eclipse.jface.action.ContributionManager;
import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.events.RefsChangedEvent;
import org.eclipse.jgit.events.RefsChangedListener;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.SharedHeaderFormEditor;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.progress.UIJob;
/**
* Editor class to view a commit in a form editor.
*/
public class CommitEditor extends SharedHeaderFormEditor implements
RefsChangedListener, IShowInSource {
/**
* ID - editor id
*/
public static final String ID = "org.eclipse.egit.ui.commitEditor"; //$NON-NLS-1$
private static final String TOOLBAR_HEADER_ID = ID + ".header.toolbar"; //$NON-NLS-1$
/**
* Open commit in editor
*
* @param commit
* @return opened editor part
* @throws PartInitException
*/
public static final IEditorPart open(RepositoryCommit commit)
throws PartInitException {
return open(commit, true);
}
/**
* Open commit in editor
*
* @param commit
* @param activateOnOpen <code>true</code> if the newly opened editor should be activated
* @return opened editor part
* @throws PartInitException
* @since 2.1
*/
public static final IEditorPart open(RepositoryCommit commit, boolean activateOnOpen)
throws PartInitException {
CommitEditorInput input = new CommitEditorInput(commit);
return IDE.openEditor(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage(), input, ID, activateOnOpen);
}
/**
* Open commit in editor
*
* @param commit
* @param activateOnOpen <code>true</code> if the newly opened editor should be activated
* @return opened editor part or null if opening fails
* @since 2.1
*/
public static final IEditorPart openQuiet(RepositoryCommit commit, boolean activateOnOpen) {
try {
return open(commit, activateOnOpen);
} catch (PartInitException e) {
Activator.logError(e.getMessage(), e);
return null;
}
}
/**
* Open commit in editor
*
* @param commit
* @return opened editor part or null if opening fails
*/
public static final IEditorPart openQuiet(RepositoryCommit commit) {
return openQuiet(commit, true);
}
private CommitEditorPage commitPage;
private DiffEditorPage diffPage;
private NotesEditorPage notePage;
private ListenerHandle refListenerHandle;
/**
* @see org.eclipse.ui.forms.editor.FormEditor#addPages()
*/
protected void addPages() {
try {
if (getCommit().isStash())
commitPage = new StashEditorPage(this);
else
commitPage = new CommitEditorPage(this);
addPage(commitPage);
diffPage = new DiffEditorPage(this);
addPage(diffPage);
if (getCommit().getNotes().length > 0) {
notePage = new NotesEditorPage(this);
addPage(notePage);
}
} catch (PartInitException e) {
Activator.error("Error adding page", e); //$NON-NLS-1$
}
refListenerHandle = Repository.getGlobalListenerList()
.addRefsChangedListener(this);
}
private CommandContributionItem createCommandContributionItem(
String commandId) {
CommandContributionItemParameter parameter = new CommandContributionItemParameter(
getSite(), commandId, commandId,
CommandContributionItem.STYLE_PUSH);
return new CommandContributionItem(parameter);
}
/**
* @see org.eclipse.ui.forms.editor.SharedHeaderFormEditor#createHeaderContents(org.eclipse.ui.forms.IManagedForm)
*/
protected void createHeaderContents(IManagedForm headerForm) {
RepositoryCommit commit = getCommit();
ScrolledForm form = headerForm.getForm();
String commitName = commit.getRevCommit().name();
String title = getFormattedHeaderTitle(commitName);
new HeaderText(form.getForm(), title, commitName);
form.setToolTipText(commitName);
getToolkit().decorateFormHeading(form.getForm());
IToolBarManager toolbar = form.getToolBarManager();
ControlContribution repositoryLabelControl = new ControlContribution(
"repositoryLabel") { //$NON-NLS-1$
@Override
protected Control createControl(Composite parent) {
FormToolkit toolkit = getHeaderForm().getToolkit();
Composite composite = toolkit.createComposite(parent);
RowLayout layout = new RowLayout();
composite.setLayout(layout);
composite.setBackground(null);
String label = getCommit().getRepositoryName();
ImageHyperlink link = new ImageHyperlink(composite, SWT.NONE);
link.setText(label);
link.setFont(JFaceResources.getBannerFont());
link.setForeground(toolkit.getColors().getColor(
IFormColors.TITLE));
link.setToolTipText(UIText.CommitEditor_showGitRepo);
link.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent event) {
RepositoriesView view;
try {
view = (RepositoriesView) PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage()
.showView(RepositoriesView.VIEW_ID);
view.showRepository(getCommit().getRepository());
} catch (PartInitException e) {
Activator.handleError(
UIText.CommitEditor_couldNotShowRepository,
e, false);
}
}
});
return composite;
}
};
toolbar.add(repositoryLabelControl);
if (commit.isStash()) {
toolbar.add(createCommandContributionItem(StashApplyHandler.ID));
toolbar.add(createCommandContributionItem(StashDropHandler.ID));
} else {
toolbar.add(createCommandContributionItem(CreateTagHandler.ID));
toolbar.add(createCommandContributionItem(CreateBranchHandler.ID));
toolbar.add(createCommandContributionItem(CheckoutHandler.ID));
toolbar.add(createCommandContributionItem(CherryPickHandler.ID));
toolbar.add(createCommandContributionItem(RevertHandler.ID));
toolbar.add(createCommandContributionItem(ShowInHistoryHandler.ID));
}
addContributions(toolbar);
toolbar.update(true);
getSite().setSelectionProvider(new ISelectionProvider() {
public void setSelection(ISelection selection) {
// Ignored
}
public void removeSelectionChangedListener(
ISelectionChangedListener listener) {
// Ignored
}
public ISelection getSelection() {
return new StructuredSelection(getCommit());
}
public void addSelectionChangedListener(
ISelectionChangedListener listener) {
// Ignored
}
});
}
private String getFormattedHeaderTitle(String commitName) {
if (getCommit().isStash()) {
int stashIndex = getStashIndex(getCommit().getRepository(),
getCommit().getRevCommit().getId());
String stashName = MessageFormat.format("stash@'{'{0}'}'", //$NON-NLS-1$
Integer.valueOf(stashIndex));
return MessageFormat.format(
UIText.CommitEditor_TitleHeaderStashedCommit,
stashName);
} else {
return MessageFormat.format(UIText.CommitEditor_TitleHeaderCommit,
commitName);
}
}
private int getStashIndex(Repository repo, ObjectId id) {
int index = 0;
try {
for (RevCommit commit : Git.wrap(repo).stashList().call())
if (commit.getId().equals(id))
return index;
else
index++;
throw new IllegalStateException(
UIText.CommitEditor_couldNotFindStashCommit);
} catch (Exception e) {
String message = MessageFormat.format(
UIText.CommitEditor_couldNotGetStashIndex, id.name());
Activator.logError(message, e);
index = -1;
}
return index;
}
/**
* @see org.eclipse.ui.forms.editor.SharedHeaderFormEditor#setFocus()
* @since 2.0
*/
@Override
public void setFocus() {
commitPage.getPartControl().setFocus();
}
private void addContributions(IToolBarManager toolBarManager) {
IMenuService menuService = CommonUtils.getService(getSite(), IMenuService.class);
if (menuService != null
&& toolBarManager instanceof ContributionManager) {
ContributionManager contributionManager = (ContributionManager) toolBarManager;
String toolbarUri = "toolbar:" + TOOLBAR_HEADER_ID; //$NON-NLS-1$
menuService.populateContributionManager(contributionManager,
toolbarUri);
}
}
private RepositoryCommit getCommit() {
return (RepositoryCommit) getAdapter(RepositoryCommit.class);
}
/**
* @see org.eclipse.ui.part.MultiPageEditorPart#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (RepositoryCommit.class == adapter)
return getEditorInput().getAdapter(adapter);
return super.getAdapter(adapter);
}
/**
* @see org.eclipse.ui.forms.editor.FormEditor#init(org.eclipse.ui.IEditorSite,
* org.eclipse.ui.IEditorInput)
*/
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
if (input.getAdapter(RepositoryCommit.class) == null)
throw new PartInitException(
"Input could not be adapted to commit object"); //$NON-NLS-1$
super.init(site, input);
setPartName(input.getName());
setTitleToolTip(input.getToolTipText());
}
public void dispose() {
refListenerHandle.remove();
super.dispose();
}
/**
* @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
*/
public void doSave(IProgressMonitor monitor) {
// Save not supported
}
/**
* @see org.eclipse.ui.part.EditorPart#doSaveAs()
*/
public void doSaveAs() {
// Save as not supported
}
/**
* @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
*/
public boolean isSaveAsAllowed() {
return false;
}
public void onRefsChanged(RefsChangedEvent event) {
if (getCommit().getRepository().getDirectory()
.equals(event.getRepository().getDirectory())) {
UIJob job = new UIJob("Refreshing editor") { //$NON-NLS-1$
public IStatus runInUIThread(IProgressMonitor monitor) {
if (!getContainer().isDisposed())
commitPage.refresh();
return Status.OK_STATUS;
}
};
job.schedule();
}
}
public ShowInContext getShowInContext() {
if (commitPage != null && commitPage.isActive())
return commitPage.getShowInContext();
else
return null;
}
}