com.microsoft.tfs.client.common.ui.feedback.FeedbackDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.client.common.ui.feedback.FeedbackDialog.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the repository root.

package com.microsoft.tfs.client.common.ui.feedback;

import java.net.URI;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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.graphics.Font;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.microsoft.tfs.client.common.ui.Messages;
import com.microsoft.tfs.client.common.ui.browser.BrowserFacade;
import com.microsoft.tfs.client.common.ui.browser.BrowserFacade.LaunchMode;
import com.microsoft.tfs.client.common.ui.controls.generic.compatibility.link.CompatibilityLinkControl;
import com.microsoft.tfs.client.common.ui.controls.generic.compatibility.link.CompatibilityLinkFactory;
import com.microsoft.tfs.client.common.ui.framework.dialog.BaseDialog;
import com.microsoft.tfs.client.common.ui.framework.helper.FontHelper;
import com.microsoft.tfs.client.common.ui.framework.helper.SWTUtil;
import com.microsoft.tfs.client.common.ui.framework.layout.GridDataBuilder;
import com.microsoft.tfs.client.common.ui.framework.validation.AbstractTextControlValidator;
import com.microsoft.tfs.client.common.ui.framework.validation.ButtonValidatorBinding;
import com.microsoft.tfs.core.util.URIUtils;
import com.microsoft.tfs.util.StringUtil;
import com.microsoft.tfs.util.email.EmailAddressParser;
import com.microsoft.tfs.util.valid.IValidity;
import com.microsoft.tfs.util.valid.Validity;

public class FeedbackDialog extends BaseDialog {

    private static final Log log = LogFactory.getLog(FeedbackDialog.class);

    // This is the same URI used by Visual Studio & IntellJ Send a Smile
    private static final URI URL_PRIVACY_POLICY = URIUtils.newURI("http://go.microsoft.com/fwlink/?LinkID=277167"); //$NON-NLS-1$

    // Right now the limit on properties is 1024 in AppInsights
    private static final int MAX_APP_INSIGHTS_PROPERTY_SIZE = 1024;

    private final boolean smile;

    private Text commentText;
    private Text emailText;
    private EmailAddressValidator validator;
    private Label emailErrorMessageLabel;
    private Font emailErrorMessageFont;

    private String commentString;
    private String emailString;

    public FeedbackDialog(final Shell parentShell, final boolean smile) {
        super(parentShell);
        this.smile = smile;
        setOptionResizable(true);

        // rename the label
        final String okLabel = smile ? Messages.getString("FeedbackDialog.OkButtonText.Smile") //$NON-NLS-1$
                : Messages.getString("FeedbackDialog.OkButtonText.Frown"); //$NON-NLS-1$

        setOptionIncludeDefaultButtons(false);
        addButtonDescription(IDialogConstants.OK_ID, okLabel, true);
        addButtonDescription(IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    }

    @Override
    protected String provideDialogTitle() {
        return Messages.getString("FeedbackDialog.Title"); //$NON-NLS-1$
    }

    @Override
    protected void hookAddToDialogArea(Composite dialogArea) {
        final GridLayout layout = new GridLayout();
        layout.marginWidth = getHorizontalMargin();
        layout.marginHeight = getVerticalMargin();
        layout.horizontalSpacing = getHorizontalSpacing();
        layout.verticalSpacing = getVerticalSpacing();
        dialogArea.setLayout(layout);

        final Label headerLabel = SWTUtil.createLabel(dialogArea, Messages.getString("FeedbackDialog.HeaderLabel"));//$NON-NLS-1$
        GridDataBuilder.newInstance().hSpan(layout).hFill().hGrab().applyTo(headerLabel);

        final String messageString = smile ? Messages.getString("FeedbackDialog.CommentLabel.Smile") //$NON-NLS-1$
                : Messages.getString("FeedbackDialog.CommentLabel.Frown"); //$NON-NLS-1$

        final Label messageLabel = SWTUtil.createLabel(dialogArea, messageString);
        GridDataBuilder.newInstance().hSpan(layout).hFill().hGrab().applyTo(messageLabel);

        commentText = new Text(dialogArea, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL);
        GridData commentTextGridData = GridDataBuilder.newInstance().hSpan(layout)
                .wHint(getMinimumMessageAreaWidth()).hFill().hGrab().vFill().vGrab().getGridData();

        // show five lines of text
        final GC gc = new GC(commentText);
        final FontMetrics fm = gc.getFontMetrics();
        final int commentTextFontHeight = fm.getHeight();
        gc.dispose();
        commentTextGridData.heightHint = commentTextFontHeight * 5;

        commentText.setLayoutData(commentTextGridData);
        commentText.setTextLimit(MAX_APP_INSIGHTS_PROPERTY_SIZE);
        // prevent the text from grabbing tabs
        commentText.addTraverseListener(new TraverseListener() {
            @Override
            public void keyTraversed(TraverseEvent e) {
                if (e.detail == SWT.TRAVERSE_TAB_NEXT || e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
                    e.doit = true;
                }
            }
        });

        final Label emailLabel = SWTUtil.createLabel(dialogArea, Messages.getString("FeedbackDialog.EmailLabel"));//$NON-NLS-1$
        GridDataBuilder.newInstance().hSpan(layout).hFill().hGrab().applyTo(emailLabel);

        emailText = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
        GridDataBuilder.newInstance().hSpan(layout).hFill().hGrab().applyTo(emailText);
        emailText.setTextLimit(MAX_APP_INSIGHTS_PROPERTY_SIZE);

        /*
         * Create a validator for the email textbox. Make sure to hook up the
         * text box modifier listeners (if any) after the validator so that the
         * validator gets run before the validation of all fields.
         */
        validator = new EmailAddressValidator(emailText);

        emailErrorMessageLabel = SWTUtil.createLabel(dialogArea, SWT.WRAP, StringUtil.EMPTY);
        emailErrorMessageFont = new Font(getShell().getDisplay(),
                FontHelper.italicize(emailErrorMessageLabel.getFont().getFontData()));
        emailErrorMessageLabel.setFont(emailErrorMessageFont);
        /*
         * Reserve three lines for the error messages. They could be pretty
         * wordy.
         */
        GridDataBuilder.newInstance().hSpan(layout).hFill().hGrab().hHint(commentTextFontHeight * 3)
                .applyTo(emailErrorMessageLabel);

        emailErrorMessageLabel.addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(final DisposeEvent e) {
                if (emailErrorMessageFont != null) {
                    emailErrorMessageFont.dispose();
                }
            }
        });

        final Label thankYouLabel = SWTUtil.createLabel(dialogArea, SWT.WRAP,
                Messages.getString("FeedbackDialog.ThankYouLabel")); //$NON-NLS-1$
        GridDataBuilder.newInstance().hSpan(layout).vIndent(getVerticalSpacing())
                .wHint(getMinimumMessageAreaWidth()).hFill().hGrab().applyTo(thankYouLabel);

        final CompatibilityLinkControl privacyLink = CompatibilityLinkFactory.createLink(dialogArea, SWT.NONE);
        GridDataBuilder.newInstance().hSpan(layout).hFill().hGrab().applyTo(privacyLink.getControl());
        privacyLink.setSimpleText(Messages.getString("FeedbackDialog.PrivacyLink")); //$NON-NLS-1$
        privacyLink.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
                // Use external dialog since this is being launched from a
                // dialog, and therefore would be hidden by this dialog if
                // launched internally
                BrowserFacade.launchURL(URL_PRIVACY_POLICY, null, null, null, LaunchMode.EXTERNAL);
            }
        });
    }

    @Override
    protected void hookAfterButtonsCreated() {
        new ButtonValidatorBinding(getButton(IDialogConstants.OK_ID)).bind(validator);
    }

    @Override
    protected void okPressed() {
        // grab the values
        // If there are new lines or carriage returns the events do not go
        // through.
        // TODO -- move this lower in the stack?
        commentString = commentText.getText().replaceAll("\\n|\\r", " ");//$NON-NLS-1$ //$NON-NLS-2$
        emailString = emailText.getText() == null ? StringUtil.EMPTY : emailText.getText().trim();
        super.okPressed();
    }

    public String getComment() {
        return commentString;
    }

    public String getEmail() {
        return emailString;
    }

    public class EmailAddressValidator extends AbstractTextControlValidator {

        private final EmailAddressParser parser;

        public EmailAddressValidator(final Text subject) {
            super(subject);
            parser = new EmailAddressParser();
            validate();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected IValidity computeValidity(String text) {
            if (emailErrorMessageLabel == null) {
                /*
                 * Not all controls are created yet.
                 */
                return Validity.VALID;
            }

            if (parser.parse(text)) {
                emailErrorMessageLabel.setText(StringUtil.EMPTY);
                return Validity.VALID;
            } else {
                final String erorMessage = parser.getErrorMessage();
                emailErrorMessageLabel.setText(erorMessage);
                return Validity.invalid(erorMessage);
            }
        }
    }
}