org.eclipse.egit.ui.internal.gerrit.GerritConfigurationPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.egit.ui.internal.gerrit.GerritConfigurationPage.java

Source

/*******************************************************************************
 * Copyright (C) 2011, Stefan Lay <stefan.lay@sap.com>
 * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com>
 *
 * 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.gerrit;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIUtils;
import org.eclipse.egit.ui.internal.SWTUtils;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.components.RepositorySelectionPage.Protocol;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.osgi.util.NLS;
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.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;

/**
 * Wizard page that offers simplified configuration if upstream repository
 * is hosted by Gerrit.
 */
class GerritConfigurationPage extends WizardPage {

    private final static int GERRIT_DEFAULT_SSH_PORT = 29418;

    private static final String GERRIT_HTTP_PATH_PREFIX = "/p"; //$NON-NLS-1$

    private String helpContext = null;

    private Text branch;

    private Group pushConfigurationGroup;

    private Group fetchConfigurationGroup;

    private Group uriGroup;

    private Combo scheme;

    private Text uriText;

    private URIish pushURI;

    private Text user;

    private int eventDepth;

    private final Repository repository;

    private final String remoteName;

    /**
     * @param repository the respository
     * @param remoteName the remote name
     *
     */
    public GerritConfigurationPage(Repository repository, String remoteName) {
        super(GerritConfigurationPage.class.getName());
        this.repository = repository;
        this.remoteName = remoteName;
        setTitle(UIText.GerritConfigurationPage_title);
        String repositoryName = Activator.getDefault().getRepositoryUtil().getRepositoryName(repository);
        setDescription(
                MessageFormat.format(UIText.GerritConfigurationPage_PageDescription, remoteName, repositoryName));

    }

    public void createControl(Composite parent) {
        final Composite panel = new Composite(parent, SWT.NULL);
        final GridLayout layout = new GridLayout();
        layout.numColumns = 1;
        panel.setLayout(layout);

        createURIGroup(panel);
        createPushConfigurationGroup(panel);
        createFetchConfigurationGroup(panel);

        Dialog.applyDialogFont(panel);
        setControl(panel);
        uriText.setFocus();
    }

    private void createURIGroup(Composite panel) {
        uriGroup = SWTUtils.createHFillGroup(panel, UIText.GerritConfigurationPage_pushUri,
                SWTUtils.MARGINS_DEFAULT, 2);

        scheme = new Combo(uriGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
        uriText = SWTUtils.createText(uriGroup);

        new Label(uriGroup, SWT.NULL).setText(UIText.GerritConfigurationPage_UserLabel);
        user = SWTUtils.createText(uriGroup);
        user.addModifyListener(new ModifyListener() {
            public void modifyText(final ModifyEvent e) {
                eventDepth++;
                try {
                    if (eventDepth == 1) {
                        if (pushURI != null) {
                            pushURI = pushURI.setUser(user.getText());
                            uriText.setText(pushURI.toString());
                            checkPage();
                        }
                    }
                } finally {
                    eventDepth--;
                }
            }
        });

        uriText.addModifyListener(new ModifyListener() {
            public void modifyText(final ModifyEvent e) {
                eventDepth++;
                try {
                    if (eventDepth == 1) {
                        URIish u = new URIish(uriText.getText());
                        String newUser = u.getUser();
                        user.setText(newUser != null ? newUser : ""); //$NON-NLS-1$
                    }
                } catch (URISyntaxException e1) {
                    // empty
                } finally {
                    eventDepth--;
                }
                checkPage();
            }
        });

        for (Protocol p : Protocol.values()) {
            scheme.add(p.getDefaultScheme());
        }
        scheme.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(final SelectionEvent e) {
                URIish oldPushURI = pushURI;
                final int idx = scheme.getSelectionIndex();
                pushURI = pushURI.setScheme(scheme.getItem(idx));

                if (Protocol.SSH.handles(pushURI))
                    pushURI = pushURI.setPort(GERRIT_DEFAULT_SSH_PORT);
                else
                    pushURI = pushURI.setPort(-1);

                if (isHttpProtocol(pushURI))
                    pushURI = prependGerritHttpPathPrefix(pushURI);
                else if (isHttpProtocol(oldPushURI))
                    pushURI = removeGerritHttpPathPrefix(pushURI);

                uriText.setText(pushURI.toString());
                scheme.setToolTipText(Protocol.values()[idx].getTooltip());
            }
        });
    }

    private void createPushConfigurationGroup(Composite panel) {
        pushConfigurationGroup = SWTUtils.createHFillGroup(panel, UIText.GerritConfigurationPage_groupPush,
                SWTUtils.MARGINS_DEFAULT, 3);
        Label branchLabel = new Label(pushConfigurationGroup, SWT.NULL);
        branchLabel.setText(UIText.GerritConfigurationPage_labelDestinationBranch);
        // we visualize the prefix here
        Text prefix = new Text(pushConfigurationGroup, SWT.READ_ONLY);
        prefix.setText("refs/for/"); //$NON-NLS-1$
        prefix.setEnabled(false);

        branch = SWTUtils.createText(pushConfigurationGroup);
        branch.addModifyListener(new ModifyListener() {
            public void modifyText(final ModifyEvent e) {
                checkPage();
            }
        });

        // give focus to the branch if label is activated using the mnemonic
        branchLabel.addTraverseListener(new TraverseListener() {
            public void keyTraversed(TraverseEvent e) {
                branch.setFocus();
                branch.selectAll();
            }
        });
        addRefContentProposalToText(branch);
    }

    private void createFetchConfigurationGroup(Composite panel) {
        fetchConfigurationGroup = SWTUtils.createHFillGroup(panel, UIText.GerritConfigurationPage_groupFetch,
                SWTUtils.MARGINS_DEFAULT, 2);
        new Label(fetchConfigurationGroup, SWT.NULL)
                .setText(UIText.GerritConfigurationPage_ConfigureFetchReviewNotes);
    }

    /**
     * @return the push URI for Gerrit code review
     */
    public URIish getURI() {
        return pushURI;
    }

    /**
     * @return the branch used in the gerrit push refspec: refs/for/branch
     */
    public String getBranch() {
        return branch.getText();
    }

    /**
     * Set the ID for context sensitive help
     *
     * @param id
     *            help context
     */
    public void setHelpContext(String id) {
        helpContext = id;
    }

    @Override
    public void performHelp() {
        PlatformUI.getWorkbench().getHelpSystem().displayHelp(helpContext);
    }

    /**
     * @param uri the URI of the source repository
     */
    public void setSelection(URIish uri) {
        setSelection(uri, null);
    }

    /**
     * @param uri
     *            the URI of the source repository
     * @param targetBranch
     */
    public void setSelection(URIish uri, String targetBranch) {

        setDefaults(uri, targetBranch);
        checkPage();
    }

    private void setDefaults(URIish uri, String targetBranch) {
        URIish newPushURI = uri;
        if (Protocol.SSH.handles(uri)) {
            newPushURI = newPushURI.setPort(GERRIT_DEFAULT_SSH_PORT);
        } else if (Protocol.GIT.handles(uri)) {
            newPushURI = newPushURI.setScheme(Protocol.SSH.getDefaultScheme());
            newPushURI = newPushURI.setPort(GERRIT_DEFAULT_SSH_PORT);
        } else if (isHttpProtocol(uri)) {
            newPushURI = prependGerritHttpPathPrefix(newPushURI);
        }
        uriText.setText(newPushURI.toString());
        final String uriScheme = newPushURI.getScheme();
        if (uriScheme != null)
            scheme.select(scheme.indexOf(uriScheme));
        branch.setText(targetBranch != null ? targetBranch : Constants.MASTER);
    }

    private boolean isHttpProtocol(URIish uri) {
        return Protocol.HTTP.handles(uri) || Protocol.HTTPS.handles(uri);
    }

    /**
     * @param u
     * @return URI with path prefixed for Gerrit smart HTTP support
     */
    private URIish prependGerritHttpPathPrefix(URIish u) {
        String path = u.getPath();
        if (!path.startsWith(GERRIT_HTTP_PATH_PREFIX))
            return u.setPath(GERRIT_HTTP_PATH_PREFIX + path);
        return u;
    }

    /**
     * @param u
     * @return URI without Gerrit smart HTTP path prefix
     */
    private URIish removeGerritHttpPathPrefix(URIish u) {
        String path = u.getPath();
        if (path.startsWith(GERRIT_HTTP_PATH_PREFIX))
            return u.setPath(path.substring(4));
        return u;
    }

    private void checkPage() {
        try {
            pushURI = new URIish(uriText.getText());
            scheme.select(scheme.indexOf(pushURI.getScheme()));
        } catch (URISyntaxException e) {
            setErrorMessage(e.getLocalizedMessage());
            setPageComplete(false);
            return;
        }
        String branchName = branch.getText();
        if (branchName.length() == 0) {
            setErrorMessage(UIText.GerritConfigurationPage_errorBranchName);
            setPageComplete(false);
            return;
        }

        setErrorMessage(null);
        setPageComplete(true);
    }

    private void addRefContentProposalToText(final Text textField) {
        KeyStroke stroke;
        try {
            stroke = KeyStroke.getInstance("CTRL+SPACE"); //$NON-NLS-1$
            UIUtils.addBulbDecorator(textField,
                    NLS.bind(UIText.GerritConfigurationPage_BranchTooltipHover, stroke.format()));
        } catch (ParseException e1) {
            Activator.handleError(e1.getMessage(), e1, false);
            stroke = null;
        }

        IContentProposalProvider cp = new IContentProposalProvider() {
            public IContentProposal[] getProposals(String contents, int position) {
                List<IContentProposal> resultList = new ArrayList<IContentProposal>();

                // make the simplest possible pattern check: allow "*"
                // for multiple characters
                String patternString = contents;
                // ignore spaces in the beginning
                while (patternString.length() > 0 && patternString.charAt(0) == ' ') {
                    patternString = patternString.substring(1);
                }

                // we quote the string as it may contain spaces
                // and other stuff colliding with the Pattern
                patternString = Pattern.quote(patternString);

                patternString = patternString.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$

                // make sure we add a (logical) * at the end
                if (!patternString.endsWith(".*")) //$NON-NLS-1$
                    patternString = patternString + ".*"; //$NON-NLS-1$

                // let's compile a case-insensitive pattern (assumes ASCII only)
                Pattern pattern;
                try {
                    pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
                } catch (PatternSyntaxException e) {
                    pattern = null;
                }

                Set<String> proposals = new TreeSet<String>();

                try {
                    // propose the names of the remote tracking
                    // branches for the given remote
                    Set<String> remotes = repository.getRefDatabase()
                            .getRefs(Constants.R_REMOTES + remoteName + "/").keySet(); //$NON-NLS-1$
                    proposals.addAll(remotes);
                } catch (IOException e) {
                    // simply ignore, no proposals then
                }

                for (final String proposal : proposals) {
                    if (pattern != null && !pattern.matcher(proposal).matches())
                        continue;
                    IContentProposal propsal = new BranchContentProposal(proposal);
                    resultList.add(propsal);
                }

                return resultList.toArray(new IContentProposal[resultList.size()]);
            }
        };

        ContentProposalAdapter adapter = new ContentProposalAdapter(textField, new TextContentAdapter(), cp, stroke,
                null);
        // set the acceptance style to always replace the complete content
        adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
    }

    private final static class BranchContentProposal implements IContentProposal {
        private final String myString;

        BranchContentProposal(String string) {
            myString = string;
        }

        public String getContent() {
            return myString;
        }

        public int getCursorPosition() {
            return 0;
        }

        public String getDescription() {
            return myString;
        }

        public String getLabel() {
            return myString;
        }

        @Override
        public String toString() {
            return getContent();
        }
    }

}