org.eclipse.egit.gitflow.ui.internal.dialogs.InitDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.egit.gitflow.ui.internal.dialogs.InitDialog.java

Source

/*******************************************************************************
 * Copyright (C) 2015, Max Hohenegger <eclipse@hohenegger.eu>
 *
 * 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.gitflow.ui.internal.dialogs;

import static org.eclipse.core.databinding.UpdateValueStrategy.POLICY_ON_REQUEST;
import static org.eclipse.core.databinding.beans.PojoProperties.value;
import static org.eclipse.egit.gitflow.InitParameters.DEVELOP_BRANCH_PROPERTY;
import static org.eclipse.egit.gitflow.InitParameters.FEATURE_BRANCH_PREFIX_PROPERTY;
import static org.eclipse.egit.gitflow.InitParameters.HOTFIX_BRANCH_PREFIX_PROPERTY;
import static org.eclipse.egit.gitflow.InitParameters.MASTER_BRANCH_PROPERTY;
import static org.eclipse.egit.gitflow.InitParameters.RELEASE_BRANCH_PREFIX_PROPERTY;
import static org.eclipse.egit.gitflow.InitParameters.VERSION_TAG_PROPERTY;
import static org.eclipse.egit.gitflow.ui.Activator.error;
import static org.eclipse.egit.gitflow.ui.Activator.warning;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_branchDoesNotExistYetAndWillBeCreated;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_chooseBranchNamesAndPrefixes;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_developBranch;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_featureBranchPrefix;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_hotfixBranchPrefix;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_initializeRepository;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_invalidBranchName;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_invalidPrefix;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_masterBranch;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_masterBranchIsMissing;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_releaseBranchPrefix;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_selectedMasterBranchDoesNotExistCreateNow;
import static org.eclipse.egit.gitflow.ui.internal.UIText.InitDialog_versionTagPrefix;
import static org.eclipse.jface.databinding.swt.WidgetProperties.text;
import static org.eclipse.jface.dialogs.IDialogConstants.OK_ID;
import static org.eclipse.jface.dialogs.IMessageProvider.ERROR;
import static org.eclipse.jface.dialogs.MessageDialog.openQuestion;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.eclipse.jgit.lib.Repository.isValidRefName;
import static org.eclipse.swt.SWT.Modify;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.ValidationStatusProvider;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.egit.core.op.CreateLocalBranchOperation;
import org.eclipse.egit.gitflow.GitFlowRepository;
import org.eclipse.egit.gitflow.InitParameters;
import org.eclipse.egit.gitflow.WrongGitFlowStateException;
import org.eclipse.jface.databinding.dialog.TitleAreaDialogSupport;
import org.eclipse.jface.databinding.dialog.ValidationMessageProvider;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * Dialog to gather inputs for the git flow init operation.
 */
public class InitDialog extends TitleAreaDialog {
    private static final class BranchValidator implements IValidator {
        @Override
        public IStatus validate(Object value) {
            if (value == null || !isValidRefName(R_HEADS + value)) {
                return error(NLS.bind(InitDialog_invalidBranchName, value));
            }
            return Status.OK_STATUS;
        }
    }

    private static final class BranchExistsValidator implements IValidator {
        private List<String> list;

        public BranchExistsValidator(List<Ref> branchList) {
            list = new ArrayList<>();
            for (Ref ref : branchList) {
                list.add(ref.getName());
            }
        }

        @Override
        public IStatus validate(Object value) {
            if (value == null || !list.contains(R_HEADS + value)) {
                return warning(NLS.bind(InitDialog_branchDoesNotExistYetAndWillBeCreated, value));
            }
            return Status.OK_STATUS;
        }
    }

    private Text developText;

    private InitParameters gitflowInitConfig = new InitParameters();

    private Text masterText;

    private Text featureText;

    private Text releaseText;

    private Text hotfixText;

    private Text versionTagText;

    private static final String DUMMY_POSTFIX = "dummy"; //$NON-NLS-1$

    private static final int TEXT_WIDTH = 100;

    private GitFlowRepository gfRepo;

    private List<Ref> branchList;

    /**
     * @param parentShell
     * @param gfRepo
     * @param branchList
     */
    public InitDialog(Shell parentShell, GitFlowRepository gfRepo, List<Ref> branchList) {
        super(parentShell);
        this.gfRepo = gfRepo;
        this.branchList = branchList;
    }

    @Override
    public void create() {
        super.create();
        setTitle(InitDialog_initializeRepository);
        setMessage(InitDialog_chooseBranchNamesAndPrefixes);
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        Composite area = (Composite) super.createDialogArea(parent);
        Composite container = new Composite(area, SWT.NONE);
        container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayoutFactory.swtDefaults().numColumns(4).applyTo(container);

        createInputs(container);

        DataBindingContext bindingContext = initDataBinding();

        TitleAreaDialogSupport.create(this, bindingContext)
                .setValidationMessageProvider(new ValidationMessageProvider() {
                    @Override
                    public String getMessage(ValidationStatusProvider statusProvider) {
                        if (statusProvider == null) {
                            return InitDialog_chooseBranchNamesAndPrefixes;
                        }
                        return super.getMessage(statusProvider);
                    }

                    @Override
                    public int getMessageType(ValidationStatusProvider statusProvider) {
                        int type = super.getMessageType(statusProvider);
                        Button okButton = getButton(OK_ID);
                        if (okButton != null) {
                            okButton.setEnabled(type != ERROR);
                        }

                        return type;
                    }
                });

        return area;
    }

    private void createInputs(Composite container) {
        developText = createLabeledText(container, InitDialog_developBranch);
        masterText = createLabeledText(container, InitDialog_masterBranch);
        featureText = createLabeledText(container, InitDialog_featureBranchPrefix);
        releaseText = createLabeledText(container, InitDialog_releaseBranchPrefix);
        hotfixText = createLabeledText(container, InitDialog_hotfixBranchPrefix);
        versionTagText = createLabeledText(container, InitDialog_versionTagPrefix);
    }

    private Text createLabeledText(Composite container, String label) {
        new Label(container, SWT.NONE).setText(label);
        Text result = new Text(container, SWT.BORDER);
        GridDataFactory.swtDefaults().hint(TEXT_WIDTH, SWT.DEFAULT).applyTo(result);
        return result;
    }

    private DataBindingContext initDataBinding() {
        DataBindingContext context = new DataBindingContext();

        UpdateValueStrategy noModelToTarget = new UpdateValueStrategy(false, POLICY_ON_REQUEST);

        UpdateValueStrategy developUpdateStrategy = new UpdateValueStrategy();
        developUpdateStrategy.setBeforeSetValidator(new BranchValidator());
        bind(context, noModelToTarget, developUpdateStrategy, DEVELOP_BRANCH_PROPERTY, developText);

        UpdateValueStrategy masterUpdateStrategy = new UpdateValueStrategy();
        masterUpdateStrategy.setBeforeSetValidator(new BranchValidator());
        masterUpdateStrategy.setAfterConvertValidator(new BranchExistsValidator(branchList));
        bind(context, noModelToTarget, masterUpdateStrategy, MASTER_BRANCH_PROPERTY, masterText);

        UpdateValueStrategy prefixTargetToModel = new UpdateValueStrategy();
        prefixTargetToModel.setBeforeSetValidator(new IValidator() {
            @Override
            public IStatus validate(Object value) {
                if (value == null || !isValidRefName(R_HEADS + value + DUMMY_POSTFIX)) {
                    return error(NLS.bind(InitDialog_invalidPrefix, value));
                }
                return Status.OK_STATUS;
            }
        });
        bind(context, noModelToTarget, prefixTargetToModel, FEATURE_BRANCH_PREFIX_PROPERTY, featureText);
        bind(context, noModelToTarget, prefixTargetToModel, RELEASE_BRANCH_PREFIX_PROPERTY, releaseText);
        bind(context, noModelToTarget, prefixTargetToModel, HOTFIX_BRANCH_PREFIX_PROPERTY, hotfixText);
        bind(context, noModelToTarget, prefixTargetToModel, VERSION_TAG_PROPERTY, versionTagText);

        context.updateTargets();

        return context;
    }

    private void bind(DataBindingContext dataBindingContext, UpdateValueStrategy noModelToTargetUpdate,
            UpdateValueStrategy targetToModel, String modelProperty, Text widget) {
        Binding binding = dataBindingContext.bindValue(text(Modify).observe(widget),
                value(modelProperty).observe(gitflowInitConfig), targetToModel, noModelToTargetUpdate);
        ControlDecorationSupport.create(binding, SWT.TOP | SWT.LEFT);
    }

    @Override
    protected Control createButtonBar(Composite parent) {
        // TODO: we should have options to persist the selected configuration
        return super.createButtonBar(parent);
    }

    @Override
    public boolean isHelpAvailable() {
        return false;
    }

    @Override
    protected boolean isResizable() {
        return true;
    }

    @Override
    protected void okPressed() {
        String master = gitflowInitConfig.getMaster();
        Repository repository = gfRepo.getRepository();
        if (isMasterBranchAvailable(master, repository)) {
            super.okPressed();
            return;
        }
        boolean createBranch = openQuestion(getShell(), InitDialog_masterBranchIsMissing,
                NLS.bind(InitDialog_selectedMasterBranchDoesNotExistCreateNow, master));
        if (!createBranch) {
            return;
        }

        try {
            RevCommit head = gfRepo.findHead();
            new CreateLocalBranchOperation(repository, master, head).execute(null);
        } catch (CoreException | WrongGitFlowStateException e) {
            throw new RuntimeException(e);
        }
        super.okPressed();
    }

    private boolean isMasterBranchAvailable(String master, Repository repository) {
        try {
            return repository.exactRef(R_HEADS + master) != null;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @return User inputs
     */
    @NonNull
    public InitParameters getResult() {
        return gitflowInitConfig;
    }
}