| /******************************************************************************* |
| * Copyright (C) 2011, 2016 Mathias Kinzler <mathias.kinzler@sap.com> 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: |
| * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 486594 |
| *******************************************************************************/ |
| package org.eclipse.egit.ui.internal.actions; |
| |
| import java.io.IOException; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.TreeMap; |
| |
| 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.branch.BranchOperationUI; |
| import org.eclipse.egit.ui.internal.dialogs.CheckoutDialog; |
| import org.eclipse.egit.ui.internal.repository.CreateBranchWizard; |
| import org.eclipse.egit.ui.internal.selection.SelectionUtils; |
| import org.eclipse.jface.action.ContributionItem; |
| import org.eclipse.jface.resource.ResourceManager; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.jface.wizard.WizardDialog; |
| import org.eclipse.jgit.lib.CheckoutEntry; |
| import org.eclipse.jgit.lib.ConfigConstants; |
| import org.eclipse.jgit.lib.Constants; |
| import org.eclipse.jgit.lib.Ref; |
| import org.eclipse.jgit.lib.ReflogEntry; |
| import org.eclipse.jgit.lib.ReflogReader; |
| import org.eclipse.jgit.lib.Repository; |
| 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.handlers.IHandlerService; |
| import org.eclipse.ui.menus.IWorkbenchContribution; |
| import org.eclipse.ui.services.IServiceLocator; |
| |
| /** |
| * Dynamically builds the "Switch to..." sub-menu |
| */ |
| public class SwitchToMenu extends ContributionItem implements |
| IWorkbenchContribution { |
| /** the maximum number of branches to show in the sub-menu */ |
| static final int MAX_NUM_MENU_ENTRIES = 20; |
| |
| private IHandlerService handlerService; |
| |
| private final Image branchImage; |
| |
| private final Image newBranchImage; |
| |
| private final Image checkedOutImage; |
| |
| /** |
| */ |
| public SwitchToMenu() { |
| this(null); |
| } |
| |
| /** |
| * @param id |
| */ |
| public SwitchToMenu(String id) { |
| super(id); |
| ResourceManager pluginResources = Activator.getDefault() |
| .getResourceManager(); |
| branchImage = UIIcons.getImage(pluginResources, UIIcons.BRANCH); |
| newBranchImage = UIIcons.getImage(pluginResources, |
| UIIcons.CREATE_BRANCH); |
| checkedOutImage = UIIcons.getImage(pluginResources, |
| UIIcons.CHECKED_OUT_BRANCH); |
| } |
| |
| @Override |
| public void fill(Menu menu, int index) { |
| if (handlerService == null) |
| return; |
| |
| Repository repository = SelectionUtils |
| .getRepository(handlerService.getCurrentState()); |
| if (repository != null) |
| createDynamicMenu(menu, repository); |
| } |
| |
| private void createDynamicMenu(Menu menu, final Repository repository) { |
| MenuItem newBranch = new MenuItem(menu, SWT.PUSH); |
| newBranch.setText(UIText.SwitchToMenu_NewBranchMenuLabel); |
| newBranch.setImage(newBranchImage); |
| newBranch.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| String sourceRef = repository.getConfig().getString( |
| ConfigConstants.CONFIG_WORKFLOW_SECTION, null, |
| ConfigConstants.CONFIG_KEY_DEFBRANCHSTARTPOINT); |
| CreateBranchWizard wiz = null; |
| try { |
| Ref ref = null; |
| if (sourceRef != null) { |
| ref = repository.findRef(sourceRef); |
| } |
| if (ref != null) { |
| wiz = new CreateBranchWizard(repository, ref.getName()); |
| } else { |
| wiz = new CreateBranchWizard(repository, |
| repository.getFullBranch()); |
| } |
| } catch (IOException e1) { |
| // Ignore |
| } |
| if (wiz == null) { |
| wiz = new CreateBranchWizard(repository); |
| } |
| WizardDialog dlg = new WizardDialog(e.display.getActiveShell(), |
| wiz); |
| dlg.setHelpAvailable(false); |
| dlg.open(); |
| } |
| }); |
| createSeparator(menu); |
| try { |
| String currentBranch = repository.getFullBranch(); |
| Map<String, Ref> localBranches = repository.getRefDatabase().getRefs( |
| Constants.R_HEADS); |
| TreeMap<String, Ref> sortedRefs = new TreeMap<>( |
| CommonUtils.STRING_ASCENDING_COMPARATOR); |
| |
| // Add the MAX_NUM_MENU_ENTRIES most recently used branches first |
| ReflogReader reflogReader = repository.getReflogReader( |
| Constants.HEAD); |
| List<ReflogEntry> reflogEntries; |
| if (reflogReader == null) { |
| reflogEntries = Collections.emptyList(); |
| } else { |
| reflogEntries = reflogReader.getReverseEntries(); |
| } |
| for (ReflogEntry entry : reflogEntries) { |
| CheckoutEntry checkout = entry.parseCheckout(); |
| if (checkout != null) { |
| Ref ref = localBranches.get(checkout.getFromBranch()); |
| if (ref != null) |
| if (sortedRefs.size() < MAX_NUM_MENU_ENTRIES) |
| sortedRefs.put(checkout.getFromBranch(), ref); |
| ref = localBranches.get(checkout.getToBranch()); |
| if (ref != null) |
| if (sortedRefs.size() < MAX_NUM_MENU_ENTRIES) |
| sortedRefs.put(checkout.getToBranch(), ref); |
| } |
| } |
| |
| // Add the recently used branches to the menu, in alphabetical order |
| int itemCount = 0; |
| for (final Entry<String, Ref> entry : sortedRefs.entrySet()) { |
| itemCount++; |
| final String shortName = entry.getKey(); |
| final String fullName = entry.getValue().getName(); |
| createMenuItem(menu, repository, currentBranch, fullName, shortName); |
| // Do not duplicate branch names |
| localBranches.remove(shortName); |
| } |
| |
| if (itemCount < MAX_NUM_MENU_ENTRIES) { |
| // A separator between recently used branches and local branches is |
| // nice but only if we have both recently used branches and other |
| // local branches |
| if (itemCount > 0 && localBranches.size() > 0) |
| createSeparator(menu); |
| |
| // Now add more other branches if we have only a few branch switches |
| // Sort the remaining local branches |
| sortedRefs.clear(); |
| sortedRefs.putAll(localBranches); |
| for (final Entry<String, Ref> entry : sortedRefs.entrySet()) { |
| itemCount++; |
| // protect ourselves against a huge sub-menu |
| if (itemCount > MAX_NUM_MENU_ENTRIES) |
| break; |
| final String fullName = entry.getValue().getName(); |
| final String shortName = entry.getKey(); |
| createMenuItem(menu, repository, currentBranch, fullName, shortName); |
| } |
| } |
| if (itemCount > 0) |
| createSeparator(menu); |
| MenuItem others = new MenuItem(menu, SWT.PUSH); |
| others.setText(UIText.SwitchToMenu_OtherMenuLabel); |
| others.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| CheckoutDialog dialog = new CheckoutDialog( |
| e.display.getActiveShell(), repository); |
| if (dialog.open() == Window.OK) { |
| BranchOperationUI |
| .checkout(repository, dialog.getRefName()) |
| .start(); |
| } |
| |
| } |
| }); |
| } catch (IOException e) { |
| Activator.handleError(e.getMessage(), e, true); |
| } |
| } |
| |
| private static MenuItem createSeparator(Menu menu) { |
| return new MenuItem(menu, SWT.SEPARATOR); |
| } |
| |
| private void createMenuItem(Menu menu, final Repository repository, |
| String currentBranch, final String fullName, String shortName) { |
| final MenuItem item = new MenuItem(menu, SWT.PUSH); |
| item.setText(shortName); |
| boolean checkedOut = currentBranch.equals(fullName); |
| if (checkedOut) |
| item.setImage(checkedOutImage); |
| else |
| item.setImage(branchImage); |
| item.setEnabled(!checkedOut); |
| item.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| BranchOperationUI.checkout(repository, fullName) |
| .start(); |
| } |
| }); |
| } |
| |
| @Override |
| public boolean isDynamic() { |
| return true; |
| } |
| |
| @Override |
| public void initialize(IServiceLocator serviceLocator) { |
| handlerService = CommonUtils.getService(serviceLocator, IHandlerService.class); |
| } |
| |
| } |