diff options
author | Mickael Istria | 2016-01-08 13:28:03 +0000 |
---|---|---|
committer | Thomas Wolf | 2016-02-13 12:13:06 +0000 |
commit | c6a421bcccd8b07382af86e00781f03e2118c00b (patch) | |
tree | 4b2de0dcac4946cdadde22ff514d06c7f4afea96 /org.eclipse.egit.ui | |
parent | 292099f2d5bfbd6acff3ef4de981220ca285323c (diff) | |
download | egit-c6a421bcccd8b07382af86e00781f03e2118c00b.tar.gz egit-c6a421bcccd8b07382af86e00781f03e2118c00b.tar.xz egit-c6a421bcccd8b07382af86e00781f03e2118c00b.zip |
Wizard to configure pull operation
This is accessible on project's context menu, as "Pull..." just below
"Pull".
The wizard enables the user to specify the remote or add a new one, and
also to specify the remote reference. There is content assist for
published remote references, but the user may also pull from
non-published remote refs, such as pull requests on Github or patch sets
in Gerrit.
Bug: 485124
Change-Id: I88122d3fedf10de35a0c1c233b7dd9920bb8c0c7
Signed-off-by: Mickael Istria <mistria@redhat.com>
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.egit.ui')
12 files changed, 802 insertions, 1 deletions
diff --git a/org.eclipse.egit.ui/icons/obj16/pull_with_options.png b/org.eclipse.egit.ui/icons/obj16/pull_with_options.png Binary files differnew file mode 100644 index 0000000000..264559c997 --- /dev/null +++ b/org.eclipse.egit.ui/icons/obj16/pull_with_options.png diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties index bb194a87b3..0eb5319c95 100644 --- a/org.eclipse.egit.ui/plugin.properties +++ b/org.eclipse.egit.ui/plugin.properties @@ -272,6 +272,8 @@ RepoViewHierarchicalBranchRepresenation.tooltip = Hierarchical Branch Layout RepoViewBranchCommit.tooltip = Display Latest Branch Commit ConfigureTraceCommand.name = Configure Git Debug Trace PullIntoCurrentBranchMenuLabel = P&ull +PullWithOptions.name=Pull... +PullWithOptions.tooltip=Specify remote and reference for a pull operation and run it CherryPickCommand.name = Cherry Pick SquashCommitsCommand.name = Squash Commits RewordCommitCommand.name = Reword Commit diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml index cd6f19414f..da37e720be 100644 --- a/org.eclipse.egit.ui/plugin.xml +++ b/org.eclipse.egit.ui/plugin.xml @@ -790,6 +790,17 @@ toolbarPath="org.eclipse.egit.ui" tooltip="%PullIntoCurrentBranch.tooltip"> </action> + <action + class="org.eclipse.egit.ui.internal.actions.PullWithOptionsAction" + definitionId="org.eclipse.egit.ui.team.PullWithOptions" + icon="icons/obj16/pull_with_options.png" + id="org.eclipse.egit.ui.actionpullwithoptions" + label="%PullWithOptions.name" + menubarPath="org.eclipse.egit.ui.gitmenu/repo" + style="push" + toolbarPath="org.eclipse.egit.ui" + tooltip="%PullWithOptions.tooltip"> + </action> <action class="org.eclipse.egit.ui.internal.actions.SimpleFetchAction" definitionId="org.eclipse.egit.ui.team.SimpleFetch" @@ -942,6 +953,11 @@ </command> <command categoryId="org.eclipse.egit.ui.commandCategory" + id="org.eclipse.egit.ui.team.PullWithOptions" + name="%PullWithOptions.name"> + </command> + <command + categoryId="org.eclipse.egit.ui.commandCategory" id="org.eclipse.egit.ui.team.Fetch" name="%FetchCommand.name"> </command> @@ -1196,6 +1212,36 @@ </activeWhen> </handler> <handler + commandId="org.eclipse.egit.ui.team.PullWithOptions"> + <class + class="org.eclipse.egit.ui.internal.actions.PullWithOptionsActionHandler"> + </class> + <activeWhen> + <or> + <reference + definitionId="org.eclipse.egit.ui.resourcesSingleRepository"> + </reference> + <and> + <count + value="1"> + </count> + <iterate> + <and> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode"> + </instanceof> + <not> + <test + property="GitRepository.isBare"> + </test> + </not> + </and> + </iterate> + </and> + </or> + </activeWhen> + </handler> + <handler commandId="org.eclipse.egit.ui.team.Fetch"> <class class="org.eclipse.egit.ui.internal.repository.tree.command.FetchCommand"> @@ -3147,6 +3193,30 @@ </and> </visibleWhen> </command> + <command + commandId="org.eclipse.egit.ui.team.PullWithOptions" + icon="icons/obj16/pull.png" + label="%PullWithOptions.name" + style="push"> + <visibleWhen + checkEnabled="false"> + <and> + <count + value="1"> + </count> + <iterate> + <and> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> + </instanceof> + <test + property="GitRepository.canMerge"> + </test> + </and> + </iterate> + </and> + </visibleWhen> + </command> <menu label="%RemoteSubMenu.label"> <command @@ -3873,6 +3943,17 @@ </test> </visibleWhen> </command> + <command + commandId="org.eclipse.egit.ui.team.PullWithOptions" + label="%PullWithOptions.name" + style="push"> + <visibleWhen + checkEnabled="false"> + <test + property="GitSelection.projectsSingleRepository"> + </test> + </visibleWhen> + </command> <separator name="org.eclipse.egit.ui.remoteSeparator" visible="true"> @@ -5140,6 +5221,10 @@ icon="icons/obj16/pull.png"> </image> <image + commandId="org.eclipse.egit.ui.team.PullWithOptions" + icon="icons/obj16/pull.png"> + </image> + <image commandId="org.eclipse.egit.ui.team.Reset" icon="icons/obj16/reset.gif"> </image> diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java index be2d9e64b4..f728a484fb 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java @@ -2040,6 +2040,24 @@ public class UIText extends NLS { public static String HistoryPreferencePage_toggleEmailAddresses; /** */ + public static String PullWizardPage_PageName; + + /** */ + public static String PullWizardPage_PageTitle; + + /** */ + public static String PullWizardPage_PageMessage; + + /** */ + public static String PullWizardPage_referenceLabel; + + /** */ + public static String PullWizardPage_referenceTooltip; + + /** */ + public static String PullWizardPage_ChooseReference; + + /** */ public static String PullOperationUI_ConnectionProblem; /** */ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ActionCommands.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ActionCommands.java index fb5ff006b1..41b650d9f4 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ActionCommands.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ActionCommands.java @@ -128,6 +128,9 @@ public class ActionCommands { /** "Pull from upstream configuration" action command id */ public static final String PULL_FROM_UPSTREAM_CONFIG = "org.eclipse.egit.ui.team.PullFromUpstreamConfig"; //$NON-NLS-1$ + /** "Pull with a config dialog" action command id */ + public static final String PULL_WITH_OPTIONS = "org.eclipse.egit.ui.team.PullWithOptions"; //$NON-NLS-1$ + /** "Merge Tool" action command id */ public static final String MERGE_TOOL_ACTION = "org.eclipse.egit.ui.team.MergeTool"; //$NON-NLS-1$ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullWithOptionsAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullWithOptionsAction.java new file mode 100644 index 0000000000..60ac938ecb --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullWithOptionsAction.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2016, Red Hat 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: + * Mickael Istria (Red Hat Inc.) - [485124] initial implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.actions; + +/** + * An action for asking user to specify a pull operation (via wizard) and run it + * + * @see PullWithOptionsActionHandler + */ +public class PullWithOptionsAction extends RepositoryAction { + + /** + * + */ + public PullWithOptionsAction() { + super(ActionCommands.PULL_WITH_OPTIONS, + new PullWithOptionsActionHandler()); + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullWithOptionsActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullWithOptionsActionHandler.java new file mode 100644 index 0000000000..1fc9562b6b --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullWithOptionsActionHandler.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2016, Red Hat 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: + * Mickael Istria (Red Hat Inc.) - [485124] initial implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.actions; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.egit.ui.internal.pull.PullWizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.jgit.lib.Repository; + +/** + * A handler action for asking user to specify a pull operation (via wizard) and + * run it + * + * @see PullWithOptionsAction + */ +public class PullWithOptionsActionHandler extends RepositoryActionHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + Repository repo = getRepository(); + WizardDialog dialog = new WizardDialog(getShell(event), + new PullWizard(repo)); + dialog.open(); + return null; + + } + + @Override + public boolean isEnabled() { + return getRepository() != null; + } +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullOperationUI.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullOperationUI.java index ac645a2507..ca36e0d2e4 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullOperationUI.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullOperationUI.java @@ -32,6 +32,7 @@ import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.egit.core.internal.job.RuleUtil; import org.eclipse.egit.core.op.PullOperation; +import org.eclipse.egit.core.op.PullOperation.PullReferenceConfig; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.UIPreferences; @@ -85,6 +86,21 @@ public class PullOperationUI extends JobChangeAdapter { } /** + * @param configs + */ + public PullOperationUI(Map<Repository, PullReferenceConfig> configs) { + this.repositories = configs.keySet() + .toArray(new Repository[configs.size()]); + int timeout = Activator.getDefault().getPreferenceStore() + .getInt(UIPreferences.REMOTE_CONNECTION_TIMEOUT); + pullOperation = new PullOperation(configs, timeout); + pullOperation.setCredentialsProvider(new EGitCredentialsProvider()); + for (Repository repository : repositories) { + results.put(repository, NOT_TRIED_STATUS); + } + } + + /** * Starts this operation asynchronously */ public void start() { diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullWizard.java new file mode 100644 index 0000000000..cf490ebf91 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullWizard.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2016 Red Hat 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 + *******************************************************************************/ +package org.eclipse.egit.ui.internal.pull; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.egit.core.op.PullOperation.PullReferenceConfig; +import org.eclipse.egit.ui.Activator; +import org.eclipse.egit.ui.internal.SecureStoreUtils; +import org.eclipse.egit.ui.internal.UIText; +import org.eclipse.egit.ui.internal.push.AddRemotePage; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; + +/** + * A wizard to allow to specify a pull operation with options + */ +public class PullWizard extends Wizard { + + private final Repository repository; + + private PullWizardPage page; + private AddRemotePage addRemotePage; + + /** + * @param repo + * the repository + */ + public PullWizard(final Repository repo) { + this.repository = repo; + setWindowTitle(UIText.PullWizardPage_PageTitle); + } + + @Override + public void addPages() { + Set<String> remoteNames = repository.getConfig() + .getSubsections(ConfigConstants.CONFIG_REMOTE_SECTION); + if (remoteNames.isEmpty()) { + this.addRemotePage = new AddRemotePage(repository); + addPage(this.addRemotePage); + } + this.page = new PullWizardPage(this.repository); + addPage(this.page); + } + + @Override + public boolean performFinish() { + try { + if (this.addRemotePage != null) { + storeCredentials(this.addRemotePage); + URIish uri = this.addRemotePage.getSelection().getURI(); + configureNewRemote(uri); + } + if (this.page.overrideUpstreamConfiguration()) { + configureUpstream(); + } + startPull(); + return true; + } catch (IOException e) { + Activator.logError(e.getMessage(), e); + return false; + } catch (URISyntaxException e) { + Activator.logError(e.getMessage(), e); + return false; + } + } + + private void storeCredentials(AddRemotePage remotePage) { + if (remotePage.getStoreInSecureStore()) { + URIish uri = remotePage.getSelection().getURI(); + if (uri != null) { + SecureStoreUtils.storeCredentials(remotePage.getCredentials(), + uri); + } + } + } + + private void configureNewRemote(URIish uri) + throws URISyntaxException, IOException { + StoredConfig config = repository.getConfig(); + String remoteName = this.page.getRemoteConfig().getName(); + RemoteConfig remoteConfig = new RemoteConfig(config, remoteName); + remoteConfig.addURI(uri); + RefSpec defaultFetchSpec = new RefSpec().setForceUpdate(true) + .setSourceDestination(Constants.R_HEADS + "*", //$NON-NLS-1$ + Constants.R_REMOTES + remoteName + "/*"); //$NON-NLS-1$ + remoteConfig.addFetchRefSpec(defaultFetchSpec); + remoteConfig.update(config); + config.save(); + } + + private void configureUpstream() throws IOException { + String fullBranch = this.repository.getFullBranch(); + if (fullBranch == null || !fullBranch.startsWith(Constants.R_HEADS)) { + // Don't configure upstream for detached HEAD + return; + } + String remoteName = this.page.getRemoteConfig().getName(); + String fullRemoteBranchName = this.page.getFullRemoteReference(); + + String localBranchName = this.repository.getBranch(); + StoredConfig config = repository.getConfig(); + config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, localBranchName, + ConfigConstants.CONFIG_KEY_REMOTE, remoteName); + config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, localBranchName, + ConfigConstants.CONFIG_KEY_MERGE, fullRemoteBranchName); + if (this.page.isRebaseSelected()) { + config.setBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, + localBranchName, ConfigConstants.CONFIG_KEY_REBASE, true); + } else { + // Make sure we overwrite any previous configuration + config.unset(ConfigConstants.CONFIG_BRANCH_SECTION, localBranchName, + ConfigConstants.CONFIG_KEY_REBASE); + } + + config.save(); + } + + private void startPull() { + Map<Repository, PullReferenceConfig> repos = new HashMap<>(1); + PullReferenceConfig config = new PullReferenceConfig( + this.page.getRemoteConfig().getName(), + this.page.getFullRemoteReference(), + this.page.getUpstreamConfig()); + repos.put(this.repository, config); + PullOperationUI pullOperationUI = new PullOperationUI(repos); + pullOperationUI.start(); + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullWizardPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullWizardPage.java new file mode 100644 index 0000000000..25d0c62933 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/pull/PullWizardPage.java @@ -0,0 +1,454 @@ +/******************************************************************************* + * Copyright (c) 2016 Red Hat 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 + *******************************************************************************/ +package org.eclipse.egit.ui.internal.pull; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.egit.core.op.CreateLocalBranchOperation.UpstreamConfig; +import org.eclipse.egit.ui.Activator; +import org.eclipse.egit.ui.UIUtils; +import org.eclipse.egit.ui.UIUtils.IRefListProvider; +import org.eclipse.egit.ui.internal.UIIcons; +import org.eclipse.egit.ui.internal.UIText; +import org.eclipse.egit.ui.internal.components.RefContentAssistProvider; +import org.eclipse.egit.ui.internal.components.RemoteSelectionCombo; +import org.eclipse.egit.ui.internal.components.RemoteSelectionCombo.IRemoteSelectionListener; +import org.eclipse.egit.ui.internal.components.RemoteSelectionCombo.SelectionType; +import org.eclipse.egit.ui.internal.push.AddRemoteWizard; +import org.eclipse.egit.ui.internal.push.PushBranchPage; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.window.Window; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.jgit.lib.BranchConfig; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** + * This Wizard Page allows to configure a Push operation (remote, reference, + * rebase/merge) + * + * It is heavily inspired/copy-pasted from the {@link PushBranchPage} and a lot + * of code could be factorized. + */ +public class PullWizardPage extends WizardPage { + + private RemoteSelectionCombo remoteSelectionCombo; + + private List<RemoteConfig> remoteConfigs; + private RemoteConfig remoteConfig; + + private RefContentAssistProvider assist; + + private Repository repository; + + private String fullBranch; + + private Button mergeRadio; + + private Button rebaseRadio; + + private Button rememberConfigForBranch; + + private UpstreamConfig upstreamConfig; + + private Ref head; + + private Text remoteBranchNameText; + + private ControlDecoration missingBranchDecorator; + + private boolean configureUpstream; + + /** + * Create the page. + * + * @param repository + */ + public PullWizardPage(Repository repository) { + super(UIText.PullWizardPage_PageName); + setTitle(UIText.PullWizardPage_PageTitle); + setMessage(UIText.PullWizardPage_PageMessage); + setImageDescriptor(UIIcons.WIZBAN_PULL); + this.repository = repository; + try { + this.head = repository.findRef(Constants.HEAD); + this.fullBranch = repository.getFullBranch(); + } catch (IOException ex) { + Activator.logError(ex.getMessage(), ex); + } + } + + @Override + public void createControl(Composite parent) { + try { + this.remoteConfigs = RemoteConfig + .getAllRemoteConfigs(repository.getConfig()); + Collections.sort(remoteConfigs, new Comparator<RemoteConfig>() { + @Override + public int compare(RemoteConfig first, RemoteConfig second) { + return String.CASE_INSENSITIVE_ORDER + .compare(first.getName(), second.getName()); + } + }); + setDefaultUpstreamConfig(); + } catch (URISyntaxException e) { + this.remoteConfigs = new ArrayList<RemoteConfig>(); + handleError(e); + } + + Composite res = new Composite(parent, SWT.NONE); + res.setLayout(new GridLayout(3, false)); + + Label remoteLabel = new Label(res, SWT.NONE); + remoteLabel.setText(UIText.PushBranchPage_RemoteLabel); + + this.remoteSelectionCombo = new RemoteSelectionCombo( + res, SWT.NONE, SelectionType.PUSH); + GridDataFactory.fillDefaults().grab(true, false) + .applyTo(remoteSelectionCombo); + setRemoteConfigs(); + remoteSelectionCombo + .addRemoteSelectionListener(new IRemoteSelectionListener() { + @Override + public void remoteSelected(RemoteConfig rc) { + remoteConfig = rc; + setRefAssist(rc); + checkPage(); + } + }); + + Button newRemoteButton = new Button(res, SWT.PUSH); + newRemoteButton.setText(UIText.PushBranchPage_NewRemoteButton); + GridDataFactory.fillDefaults().applyTo(newRemoteButton); + newRemoteButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + showNewRemoteDialog(); + } + }); + + Label branchNameLabel = new Label(res, SWT.NONE); + branchNameLabel.setText(UIText.PullWizardPage_referenceLabel); + branchNameLabel.setToolTipText(UIText.PullWizardPage_referenceTooltip); + + remoteBranchNameText = new Text(res, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).span(2, 1) + .applyTo(remoteBranchNameText); + UIUtils.addRefContentProposalToText(remoteBranchNameText, + this.repository, new IRefListProvider() { + + @Override + public List<Ref> getRefList() { + if (PullWizardPage.this.assist != null) { + return PullWizardPage.this.assist + .getRefsForContentAssist(false, true); + } + return Collections.emptyList(); + } + }); + remoteBranchNameText.setText(getSuggestedBranchName()); + remoteBranchNameText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + checkPage(); + } + }); + + this.mergeRadio = new Button(res, SWT.RADIO); + this.mergeRadio.setText(UIText.UpstreamConfigComponent_MergeRadio); + this.mergeRadio.setLayoutData( + new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 3, 1)); + this.mergeRadio.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + upstreamConfig = UpstreamConfig.MERGE; + } + }); + this.rebaseRadio = new Button(res, SWT.RADIO); + this.rebaseRadio.setText(UIText.UpstreamConfigComponent_RebaseRadio); + this.rebaseRadio.setLayoutData( + new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 3, 1)); + this.mergeRadio.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + upstreamConfig = UpstreamConfig.REBASE; + } + }); + this.mergeRadio + .setSelection(this.upstreamConfig == UpstreamConfig.MERGE); + this.rebaseRadio + .setSelection(this.upstreamConfig == UpstreamConfig.REBASE); + if (this.fullBranch != null + && this.fullBranch.startsWith(Constants.R_HEADS)) { + this.rememberConfigForBranch = new Button(res, SWT.CHECK); + GridData checkboxLayoutData = new GridData(SWT.BEGINNING, + SWT.CENTER, false, false, 3, 1); + checkboxLayoutData.verticalIndent = 20; + this.rememberConfigForBranch.setText( + UIText.UpstreamConfigComponent_ConfigureUpstreamCheck); + this.rememberConfigForBranch.setToolTipText( + UIText.UpstreamConfigComponent_ConfigureUpstreamToolTip); + this.rememberConfigForBranch.setLayoutData(checkboxLayoutData); + this.rememberConfigForBranch.setSelection(this.configureUpstream); + this.rememberConfigForBranch + .addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + configureUpstream = rememberConfigForBranch + .getSelection(); + checkPage(); + } + }); + } + + setPageComplete(isPageComplete()); + setControl(res); + } + + private void setRemoteConfigs() { + remoteSelectionCombo.setItems(remoteConfigs); + if (this.head != null) { + String branchName = Repository.shortenRefName(this.head.getName()); + BranchConfig branchConfig = new BranchConfig(repository.getConfig(), + branchName); + String remoteName = branchConfig.getRemote(); + if (remoteName != null) { + for (RemoteConfig rc : remoteConfigs) { + if (remoteName.equals(rc.getName())) + remoteSelectionCombo.setSelectedRemote(rc); + } + } + } + + remoteConfig = remoteSelectionCombo.getSelectedRemote(); + setRefAssist(remoteConfig); + } + + private void showNewRemoteDialog() { + AddRemoteWizard wizard = new AddRemoteWizard(repository); + WizardDialog dialog = new WizardDialog(getShell(), wizard); + int result = dialog.open(); + if (result == Window.OK) { + URIish uri = wizard.getUri(); + String remoteName = wizard.getRemoteName(); + try { + StoredConfig repoConfig = repository.getConfig(); + RemoteConfig newRemoteConfig = new RemoteConfig(repoConfig, + remoteName); + newRemoteConfig.addURI(uri); + RefSpec defaultFetchSpec = new RefSpec().setForceUpdate(true) + .setSourceDestination(Constants.R_HEADS + "*", //$NON-NLS-1$ + Constants.R_REMOTES + remoteName + "/*"); //$NON-NLS-1$ + newRemoteConfig.addFetchRefSpec(defaultFetchSpec); + newRemoteConfig.update(repoConfig); + repoConfig.save(); + List<RemoteConfig> allRemoteConfigs = RemoteConfig + .getAllRemoteConfigs(repository.getConfig()); + remoteSelectionCombo.setItems(allRemoteConfigs); + // find the new remote in the list, as the initial + // newRemoteConfig object + // isn't what's stored and returned by getAllRemoteConfigs + for (RemoteConfig current : allRemoteConfigs) { + if (newRemoteConfig.getName().equals(current.getName())) { + setSelectedRemote(current); + } + } + } catch (URISyntaxException ex) { + Activator.logError(ex.getMessage(), ex); + } catch (IOException ex) { + Activator.logError(ex.getMessage(), ex); + } + } + } + + private void setRefAssist(RemoteConfig config) { + if (config != null && config.getURIs().size() > 0) { + this.assist = new RefContentAssistProvider( + PullWizardPage.this.repository, config.getURIs().get(0), + getShell()); + } + } + + void setSelectedRemote(RemoteConfig config) { + remoteSelectionCombo.setSelectedRemote(config); + this.remoteConfig = config; + setRefAssist(this.remoteConfig); + checkPage(); + } + + @Override + public boolean isPageComplete() { + return remoteConfig != null && remoteBranchNameText.getText() != null + && !remoteBranchNameText.getText().isEmpty(); + } + + private void checkPage() { + try { + if (remoteConfig == null) { + setErrorMessage(UIText.PushBranchPage_ChooseRemoteError); + return; + } + String branchName = remoteBranchNameText.getText(); + String branchNameMessage = null; + if (branchName.length() == 0) { + branchNameMessage = MessageFormat.format( + UIText.PullWizardPage_ChooseReference, + remoteConfig.getName()); + } + if (branchNameMessage != null) { + setErrorMessage(branchNameMessage); + if (this.missingBranchDecorator == null) { + this.missingBranchDecorator = new ControlDecoration(this.remoteBranchNameText, SWT.TOP | SWT.LEFT); + this.missingBranchDecorator + .setImage(FieldDecorationRegistry.getDefault() + .getFieldDecoration( + FieldDecorationRegistry.DEC_ERROR) + .getImage()); + } + this.missingBranchDecorator + .setDescriptionText(branchNameMessage); + this.missingBranchDecorator.show(); + return; + } else if (this.missingBranchDecorator != null) { + this.missingBranchDecorator.hide(); + } + + if (overrideUpstreamConfiguration() + && hasDifferentUpstreamConfiguration()) { + setMessage(UIText.PushBranchPage_UpstreamConfigOverwriteWarning, + IMessageProvider.WARNING); + } else { + setMessage(UIText.PullWizardPage_PageMessage); + } + setErrorMessage(null); + } finally { + setPageComplete(getErrorMessage() == null); + } + } + + private void handleError(URISyntaxException e) { + Activator.handleError(e.getMessage(), e, false); + setErrorMessage(e.getMessage()); + } + + private String getSuggestedBranchName() { + if (fullBranch != null) { + String branchName = Repository.shortenRefName(fullBranch); + StoredConfig config = repository.getConfig(); + BranchConfig branchConfig = new BranchConfig(config, branchName); + String merge = branchConfig.getMerge(); + if (!branchConfig.isRemoteLocal() && merge != null + && merge.startsWith(Constants.R_HEADS)) { + return Repository.shortenRefName(merge); + } else if (merge == null + && fullBranch.startsWith(Constants.R_HEADS)) { + return branchName; + } + } + return ""; //$NON-NLS-1$ + } + + boolean overrideUpstreamConfiguration() { + return this.configureUpstream; + } + + boolean isRebaseSelected() { + return upstreamConfig == UpstreamConfig.REBASE; + } + + UpstreamConfig getUpstreamConfig() { + return this.upstreamConfig; + } + + private boolean hasDifferentUpstreamConfiguration() { + String branchName = Repository.shortenRefName(this.fullBranch); + BranchConfig branchConfig = new BranchConfig(repository.getConfig(), + branchName); + + String remote = branchConfig.getRemote(); + // No upstream config -> don't show warning + if (remote == null) + return false; + if (!remote.equals(remoteConfig.getName())) + return true; + + String merge = branchConfig.getMerge(); + if (merge == null || !merge.equals(getFullRemoteReference())) + return true; + + boolean rebase = branchConfig.isRebase(); + if (rebase != isRebaseSelected()) + return true; + + return false; + } + + private void setDefaultUpstreamConfig() { + String branchName = Repository.shortenRefName(this.fullBranch); + BranchConfig branchConfig = new BranchConfig(repository.getConfig(), + branchName); + boolean alreadyConfigured = branchConfig.getMerge() != null; + UpstreamConfig config; + if (alreadyConfigured) { + boolean rebase = branchConfig.isRebase(); + config = rebase ? UpstreamConfig.REBASE : UpstreamConfig.MERGE; + } else { + config = UpstreamConfig.getDefault(repository, Constants.R_REMOTES + + Constants.DEFAULT_REMOTE_NAME + "/" + branchName); //$NON-NLS-1$ + } + this.upstreamConfig = config; + } + + /** + * @return the chosen short name of the branch on the remote + */ + String getFullRemoteReference() { + if (!remoteBranchNameText.getText().startsWith(Constants.R_REFS)) + return Constants.R_HEADS + remoteBranchNameText.getText(); + else + return remoteBranchNameText.getText(); + } + + RemoteConfig getRemoteConfig() { + return this.remoteConfig; + } + + @Override + public void dispose() { + super.dispose(); + if (this.missingBranchDecorator != null) { + this.missingBranchDecorator.dispose(); + } + } +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/AddRemoteWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/AddRemoteWizard.java index 5fc496f466..652c63a83b 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/AddRemoteWizard.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/AddRemoteWizard.java @@ -47,7 +47,10 @@ public class AddRemoteWizard extends Wizard { return page.getSelection(); } - AddRemotePage getAddRemotePage() { + /** + * @return the wizard page + */ + public AddRemotePage getAddRemotePage() { return page; } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties index fd6d72827e..363f21446a 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties @@ -707,6 +707,12 @@ HistoryPreferencePage_MaxTagLength=&Maximum characters to show for a tag: HistoryPreferencePage_ShowGroupLabel=Show HistoryPreferencePage_ShowInRevCommentGroupLabel=Show in Revision Comment +PullWizardPage_PageName=PullWizardPage +PullWizardPage_PageTitle=Pull +PullWizardPage_PageMessage=Configure a pull operation to import remote changes. +PullWizardPage_referenceLabel=Reference: +PullWizardPage_referenceTooltip=Reference can be a branch, a tag, a commit id... +PullWizardPage_ChooseReference=Please select a reference to pull from remote \"{0}\" PullOperationUI_ConnectionProblem=Git connection problem.\ \n\nMaybe you are offline or behind a proxy.\nCheck your network connection and proxy configuration. PullOperationUI_NotTriedMessage=Not tried |