/*******************************************************************************
* Copyright (C) 2011, 2015 Dariusz Luksza <dariusz@luksza.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 static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.R_REFS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.egit.core.AdapterUtils;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.synchronize.GitModelSynchronize;
import org.eclipse.egit.ui.internal.synchronize.GitSynchronizeWizard;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectIdRef.PeeledTag;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.menus.IWorkbenchContribution;
import org.eclipse.ui.services.IServiceLocator;
/**
* Dynamic sub menu under Team > Synchronize
*/
public class SynchronizeWithMenu extends ContributionItem implements
IWorkbenchContribution {
/** the maximum number of refs to show in the sub-menu */
private static final int MAX_NUM_MENU_ENTRIES = 20;
private final Image tagImage;
private final Image branchImage;
private ISelectionService srv;
/**
*
*/
public SynchronizeWithMenu() {
this(null);
}
/**
* @param id
*/
public SynchronizeWithMenu(String id) {
super(id);
tagImage = UIIcons.TAG.createImage();
branchImage = UIIcons.BRANCH.createImage();
}
@Override
public void fill(final Menu menu, int index) {
if (srv == null)
return;
final IResource selectedResource = getSelection();
if (selectedResource == null || selectedResource.isLinked(IResource.CHECK_ANCESTORS))
return;
RepositoryMapping mapping = RepositoryMapping
.getMapping(selectedResource.getProject());
if (mapping == null)
return;
final Repository repo = mapping.getRepository();
if (repo == null)
return;
List<Ref> refs = new LinkedList<>();
RefDatabase refDatabase = repo.getRefDatabase();
try {
refs.addAll(refDatabase.getAdditionalRefs());
} catch (IOException e) {
// do nothing
}
try {
refs.addAll(refDatabase.getRefs(RefDatabase.ALL).values());
} catch (IOException e) {
// do nothing
}
Collections.sort(refs, CommonUtils.REF_ASCENDING_COMPARATOR);
String currentBranch;
try {
currentBranch = repo.getFullBranch();
} catch (IOException e) {
currentBranch = ""; //$NON-NLS-1$
}
int count = 0;
String oldName = null;
int refsLength = R_REFS.length();
int tagsLength = R_TAGS.substring(refsLength).length();
for (Ref ref : refs) {
final String name = ref.getName();
if (name.equals(Constants.HEAD) || name.equals(currentBranch) || excludeTag(ref, repo))
continue;
if (name.startsWith(R_REFS) && oldName != null
&& !oldName.regionMatches(refsLength, name, refsLength,
tagsLength))
new MenuItem(menu, SWT.SEPARATOR);
MenuItem item = new MenuItem(menu, SWT.PUSH);
item.setText(name);
if (name.startsWith(Constants.R_TAGS))
item.setImage(tagImage);
else if (name.startsWith(Constants.R_HEADS) || name.startsWith(Constants.R_REMOTES))
item.setImage(branchImage);
item.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
GitSynchronizeData data;
try {
data = new GitSynchronizeData(repo, HEAD, name, true);
if (!(selectedResource instanceof IProject)) {
HashSet<IResource> resources = new HashSet<>();
resources.add(selectedResource);
data.setIncludedResources(resources);
}
GitModelSynchronize.launch(data, new IResource[] { selectedResource });
} catch (IOException e) {
Activator.logError(e.getMessage(), e);
}
}
});
if (++count == MAX_NUM_MENU_ENTRIES)
break;
oldName = name;
}
if (count > 1)
new MenuItem(menu, SWT.SEPARATOR);
MenuItem custom = new MenuItem(menu, SWT.PUSH);
custom.setText(UIText.SynchronizeWithMenu_custom);
custom.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
GitSynchronizeWizard gitWizard = new GitSynchronizeWizard();
WizardDialog wizard = new WizardDialog(menu.getShell(),
gitWizard);
wizard.create();
wizard.open();
}
});
}
@Override
public void initialize(IServiceLocator serviceLocator) {
srv = CommonUtils.getService(serviceLocator, ISelectionService.class);
}
@Override
public boolean isDynamic() {
return true;
}
@Override
public void dispose() {
tagImage.dispose();
branchImage.dispose();
}
@Nullable
private IResource getSelection() {
ISelection sel = srv.getSelection();
if (!(sel instanceof IStructuredSelection)) {
return null;
}
Object selected = ((IStructuredSelection) sel).getFirstElement();
return AdapterUtils.adaptToAnyResource(selected);
}
private boolean excludeTag(Ref ref, Repository repo) {
if (ref instanceof PeeledTag) {
RevWalk rw = new RevWalk(repo);
try {
RevTag tag = rw.parseTag(ref.getObjectId());
return !(rw.parseAny(tag.getObject()) instanceof RevCommit);
} catch (IOException e) {
Activator.logError(e.getMessage(), e);
} finally {
rw.close();
rw.dispose();
}
}
return false;
}
}