org.eclipse.egit.ui.internal.push.PushBranchPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.egit.ui.internal.push.PushBranchPage.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2016 Robin Stocker <robin@nibor.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.push;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.egit.core.internal.Utils;
import org.eclipse.egit.core.op.CreateLocalBranchOperation;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIUtils;
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.components.UpstreamConfigComponent;
import org.eclipse.egit.ui.internal.components.UpstreamConfigComponent.UpstreamConfigSelectionListener;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.RowLayoutFactory;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.jgit.api.PullCommand;
import org.eclipse.jgit.lib.BranchConfig;
import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
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.graphics.Image;
import org.eclipse.swt.graphics.Resource;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * Page that is part of the "Push Branch..." wizard, where the user selects the
 * remote, the branch name and the upstream config.
 */
public class PushBranchPage extends WizardPage {

    private static final int MAX_SHORTCOMMIT_MESSAGE_LENGTH = 65;

    private final Repository repository;

    private final ObjectId commitToPush;

    private final Ref ref;

    private boolean showNewRemoteButton = true;

    private RemoteConfig remoteConfig;

    private List<RemoteConfig> remoteConfigs;

    private RemoteSelectionCombo remoteSelectionCombo;

    private Text remoteBranchNameText;

    private RefContentAssistProvider assist;

    private BranchRebaseMode upstreamConfig;

    private UpstreamConfigComponent upstreamConfigComponent;

    private boolean forceUpdateSelected = false;

    /** Only set if user selected "New Remote" */
    private AddRemotePage addRemotePage;

    private Set<Resource> disposables = new HashSet<>();

    /**
     * Create the page.
     *
     * @param repository
     * @param commitToPush
     * @param ref
     *            An optional ref to give hints
     */
    public PushBranchPage(Repository repository, ObjectId commitToPush, Ref ref) {
        super(UIText.PushBranchPage_PageName);
        setTitle(UIText.PushBranchPage_PageTitle);
        setMessage(UIText.PushBranchPage_PageMessage);

        this.repository = repository;
        this.commitToPush = commitToPush;
        this.ref = ref;
    }

    /**
     * @param showNewRemoteButton
     */
    public void setShowNewRemoteButton(boolean showNewRemoteButton) {
        this.showNewRemoteButton = showNewRemoteButton;
    }

    /**
     * @return the page used to add a new remote, or null if an existing remote
     *         was chosen
     */
    AddRemotePage getAddRemotePage() {
        return addRemotePage;
    }

    RemoteConfig getRemoteConfig() {
        return remoteConfig;
    }

    /**
     * @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();
    }

    BranchRebaseMode getUpstreamConfig() {
        return upstreamConfig;
    }

    boolean isForceUpdateSelected() {
        return forceUpdateSelected;
    }

    @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());
                }
            });
        } catch (URISyntaxException e) {
            this.remoteConfigs = new ArrayList<>();
            handleError(e);
        }

        Composite main = new Composite(parent, SWT.NONE);
        main.setLayout(GridLayoutFactory.swtDefaults().create());

        Composite inputPanel = new Composite(main, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(inputPanel);
        GridLayoutFactory.fillDefaults().numColumns(1).applyTo(inputPanel);

        Label sourceLabel = new Label(inputPanel, SWT.NONE);
        sourceLabel.setText(UIText.PushBranchPage_Source);

        Composite sourceComposite = new Composite(inputPanel, SWT.NONE);
        sourceComposite
                .setLayoutData(GridDataFactory.fillDefaults().indent(UIUtils.getControlIndent(), 0).create());
        RowLayout rowLayout = RowLayoutFactory.fillDefaults().create();
        rowLayout.center = true;
        sourceComposite.setLayout(rowLayout);

        if (this.ref != null) {
            Image branchIcon = UIIcons.BRANCH.createImage();
            this.disposables.add(branchIcon);

            Label branchIconLabel = new Label(sourceComposite, SWT.NONE);
            branchIconLabel.setLayoutData(new RowData(branchIcon.getBounds().width, branchIcon.getBounds().height));
            branchIconLabel.setImage(branchIcon);
            Label localBranchLabel = new Label(sourceComposite, SWT.NONE);
            localBranchLabel.setText(Repository.shortenRefName(this.ref.getName()));

            Label spacer = new Label(sourceComposite, SWT.NONE);
            spacer.setLayoutData(new RowData(3, SWT.DEFAULT));
        }

        Image commitIcon = UIIcons.CHANGESET.createImage();
        this.disposables.add(commitIcon);
        Label commitIconLabel = new Label(sourceComposite, SWT.NONE);
        commitIconLabel.setImage(commitIcon);
        commitIconLabel.setLayoutData(new RowData(commitIcon.getBounds().width, commitIcon.getBounds().height));

        Label commit = new Label(sourceComposite, SWT.NONE);
        StringBuilder commitBuilder = new StringBuilder(this.commitToPush.abbreviate(7).name());
        StringBuilder commitTooltipBuilder = new StringBuilder(this.commitToPush.getName());
        try (RevWalk revWalk = new RevWalk(repository)) {
            RevCommit revCommit = revWalk.parseCommit(this.commitToPush);
            commitBuilder.append("  "); //$NON-NLS-1$
            commitBuilder.append(Utils.shortenText(revCommit.getShortMessage(), MAX_SHORTCOMMIT_MESSAGE_LENGTH));
            commitTooltipBuilder.append("\n\n"); //$NON-NLS-1$
            commitTooltipBuilder.append(revCommit.getFullMessage());
        } catch (IOException ex) {
            commitBuilder.append(UIText.PushBranchPage_CannotAccessCommitDescription);
            commitTooltipBuilder.append(ex.getMessage());
            Activator.handleError(ex.getLocalizedMessage(), ex, false);
        }
        commit.setText(commitBuilder.toString());
        commit.setToolTipText(commitTooltipBuilder.toString());

        Label destinationLabel = new Label(inputPanel, SWT.NONE);
        destinationLabel.setText(UIText.PushBranchPage_Destination);
        GridDataFactory.fillDefaults().applyTo(destinationLabel);

        Composite remoteGroup = new Composite(inputPanel, SWT.NONE);
        remoteGroup.setLayoutData(GridDataFactory.fillDefaults().indent(UIUtils.getControlIndent(), 0).create());
        remoteGroup.setLayout(GridLayoutFactory.fillDefaults().numColumns(3).create());

        Label remoteLabel = new Label(remoteGroup, SWT.NONE);
        remoteLabel.setText(UIText.PushBranchPage_RemoteLabel);

        // Use full width in case "New Remote..." button is not shown
        int remoteSelectionSpan = showNewRemoteButton ? 1 : 2;

        remoteSelectionCombo = new RemoteSelectionCombo(remoteGroup, SWT.NONE, SelectionType.PUSH);
        GridDataFactory.fillDefaults().grab(true, false).span(remoteSelectionSpan, 1).applyTo(remoteSelectionCombo);
        setRemoteConfigs();
        remoteSelectionCombo.addRemoteSelectionListener(new IRemoteSelectionListener() {
            @Override
            public void remoteSelected(RemoteConfig rc) {
                remoteConfig = rc;
                setRefAssist(rc);
                checkPage();
            }
        });

        if (showNewRemoteButton) {
            Button newRemoteButton = new Button(remoteGroup, 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(remoteGroup, SWT.NONE);
        branchNameLabel.setText(UIText.PushBranchPage_RemoteBranchNameLabel);

        remoteBranchNameText = new Text(remoteGroup, SWT.BORDER);
        GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(remoteBranchNameText);
        remoteBranchNameText.setText(getSuggestedBranchName());
        UIUtils.addRefContentProposalToText(remoteBranchNameText, this.repository, () -> {
            if (PushBranchPage.this.assist != null) {
                return PushBranchPage.this.assist.getRefsForContentAssist(false, true);
            }
            return Collections.emptyList();
        });

        if (this.ref != null) {
            upstreamConfigComponent = new UpstreamConfigComponent(inputPanel, SWT.NONE);
            upstreamConfigComponent.getContainer().setLayoutData(
                    GridDataFactory.fillDefaults().grab(true, false).span(3, 1).indent(SWT.DEFAULT, 20).create());
            upstreamConfigComponent.addUpstreamConfigSelectionListener(new UpstreamConfigSelectionListener() {
                @Override
                public void upstreamConfigSelected(BranchRebaseMode newUpstreamConfig) {
                    upstreamConfig = newUpstreamConfig;
                    checkPage();
                }
            });
            setDefaultUpstreamConfig();
        }

        final Button forceUpdateButton = new Button(inputPanel, SWT.CHECK);
        forceUpdateButton.setText(UIText.PushBranchPage_ForceUpdateButton);
        forceUpdateButton.setSelection(false);
        forceUpdateButton.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).span(3, 1).create());
        forceUpdateButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                forceUpdateSelected = forceUpdateButton.getSelection();
            }
        });

        Link advancedDialogLink = new Link(main, SWT.NONE);
        advancedDialogLink.setText(UIText.PushBranchPage_advancedWizardLink);
        advancedDialogLink.setToolTipText(UIText.PushBranchPage_advancedWizardLinkTooltip);
        advancedDialogLink.setLayoutData(new GridData(SWT.END, SWT.END, false, true));
        advancedDialogLink.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Shell parentShell = getShell().getParent().getShell();
                PushWizard advancedWizard = null;
                try {
                    advancedWizard = new PushWizard(repository);
                    getShell().close();
                    new WizardDialog(parentShell, advancedWizard).open();
                } catch (URISyntaxException ex) {
                    Activator.logError(ex.getMessage(), ex);
                }

            }
        });

        setControl(main);

        checkPage();

        // Add listener now to avoid setText above to already trigger it.
        remoteBranchNameText.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent e) {
                checkPage();
            }
        });
    }

    private void setRemoteConfigs() {
        remoteSelectionCombo.setItems(remoteConfigs);
        if (this.ref != null) {
            String branchName = Repository.shortenRefName(this.ref.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 setDefaultUpstreamConfig() {
        if (this.ref != null) {
            String branchName = Repository.shortenRefName(ref.getName());
            BranchConfig branchConfig = new BranchConfig(repository.getConfig(), branchName);
            boolean alreadyConfigured = branchConfig.getMerge() != null;
            BranchRebaseMode config;
            if (alreadyConfigured) {
                config = PullCommand.getRebaseMode(branchName, repository.getConfig());
            } else {
                config = CreateLocalBranchOperation.getDefaultUpstreamConfig(repository,
                        Constants.R_REMOTES + Constants.DEFAULT_REMOTE_NAME + "/" + branchName); //$NON-NLS-1$
            }
            this.upstreamConfig = config;
            this.upstreamConfigComponent.setUpstreamConfig(this.upstreamConfig);
        }
    }

    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();
            addRemotePage = wizard.getAddRemotePage();
            setSelectedRemote(remoteName, uri);
        }
    }

    private void checkPage() {
        try {
            if (remoteConfig == null) {
                setErrorMessage(UIText.PushBranchPage_ChooseRemoteError);
                return;
            }
            String branchName = remoteBranchNameText.getText();
            if (branchName.length() == 0) {
                setErrorMessage(
                        MessageFormat.format(UIText.PushBranchPage_ChooseBranchNameError, remoteConfig.getName()));
                return;
            }
            if (!Repository.isValidRefName(Constants.R_HEADS + branchName)) {
                setErrorMessage(UIText.PushBranchPage_InvalidBranchNameError);
                return;
            }
            if (getUpstreamConfig() != null && hasDifferentUpstreamConfiguration()) {
                setMessage(UIText.PushBranchPage_UpstreamConfigOverwriteWarning, IMessageProvider.WARNING);
            } else {
                setMessage(UIText.PushBranchPage_PageMessage);
            }
            setErrorMessage(null);
        } finally {
            setPageComplete(getErrorMessage() == null);
        }
    }

    void setSelectedRemote(String remoteName, URIish urIish) {
        try {
            RemoteConfig config = new RemoteConfig(repository.getConfig(), remoteName);
            config.addURI(urIish);
            remoteSelectionCombo.setItems(Arrays.asList(config));
            this.remoteConfig = config;
            remoteSelectionCombo.setEnabled(false);
            setRefAssist(this.remoteConfig);
            checkPage();
        } catch (URISyntaxException e) {
            handleError(e);
        }
    }

    private String getSuggestedBranchName() {
        if (ref != null && !ref.getName().startsWith(Constants.R_REMOTES)) {
            StoredConfig config = repository.getConfig();
            String branchName = Repository.shortenRefName(ref.getName());

            BranchConfig branchConfig = new BranchConfig(config, branchName);
            String merge = branchConfig.getMerge();
            if (!branchConfig.isRemoteLocal() && merge != null && merge.startsWith(Constants.R_HEADS))
                return Repository.shortenRefName(merge);

            return branchName;
        } else {
            return ""; //$NON-NLS-1$
        }
    }

    private void setRefAssist(RemoteConfig config) {
        if (config != null && config.getURIs().size() > 0) {
            this.assist = new RefContentAssistProvider(PushBranchPage.this.repository, config.getURIs().get(0),
                    getShell());
        }
    }

    private boolean hasDifferentUpstreamConfiguration() {
        String branchName = Repository.shortenRefName(ref.getName());
        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;
        }
        if (branchConfig.getRebaseMode() != upstreamConfig) {
            return true;
        }
        return false;
    }

    private void handleError(URISyntaxException e) {
        Activator.handleError(e.getMessage(), e, false);
        setErrorMessage(e.getMessage());
    }

    @Override
    public void dispose() {
        super.dispose();
        for (Resource disposable : this.disposables)
            disposable.dispose();
    }
}