com.microsoft.tfs.client.common.ui.wit.form.controls.LabelableControl.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.client.common.ui.wit.form.controls.LabelableControl.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.wit.form.controls;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
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.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

import com.microsoft.tfs.client.common.ui.Messages;
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.launcher.Launcher;
import com.microsoft.tfs.client.common.ui.wit.dialogs.LabelableLinkSelectionDialog;
import com.microsoft.tfs.client.common.ui.wit.dialogs.LabelableLinkSelectionDialog.LabelableLinkSelectionItem;
import com.microsoft.tfs.core.clients.workitem.fields.Field;
import com.microsoft.tfs.core.clients.workitem.fields.FieldChangeEvent;
import com.microsoft.tfs.core.clients.workitem.form.WIFormControl;
import com.microsoft.tfs.core.clients.workitem.form.WIFormLabelPositionEnum;
import com.microsoft.tfs.core.clients.workitem.form.WIFormLink;
import com.microsoft.tfs.core.clients.workitem.form.WIFormReadOnlyEnum;
import com.microsoft.tfs.core.clients.workitem.form.WIFormText;
import com.microsoft.tfs.core.clients.workitem.internal.MacroTargetNotConfiguredException;

public abstract class LabelableControl extends BaseWorkItemControl {
    // A map of link-text to WIFormLink elements. This control allows multiple
    // link segments and
    // regular text segments to be intermixed. This map associates a single
    // link-text with the
    // corresponding WIFormLink element.
    //
    // Uses a list so that we can order the links for back compat.
    private final List textAndLinkList = new ArrayList();

    // columnsToTake will be >= getControlColumns()
    protected abstract void createControl(Composite parent, int columnsToTake);

    // how many columns will the createControl() method take up?
    protected abstract int getControlColumns();

    protected WIFormControl getControlDescription() {
        return (WIFormControl) getFormElement();
    }

    protected boolean isLabelOnly() {
        return false;
    }

    protected boolean isFormReadonly() {
        return getControlDescription().getReadOnly() == WIFormReadOnlyEnum.TRUE;
    }

    @Override
    public int getMinimumRequiredColumnCount() {
        if (getControlDescription().getLabelPosition() == WIFormLabelPositionEnum.TOP
                || getControlDescription().getLabelPosition() == WIFormLabelPositionEnum.BOTTOM) {
            return getControlColumns();
        }
        return getControlColumns() + 1;
    }

    @Override
    public void addToComposite(final Composite parent) {
        final int numColumns = ((GridLayout) parent.getLayout()).numColumns;
        final LinkTextData textData = getLabelTextAndLinks(getControlDescription(), textAndLinkList);

        if (textData != null) {
            CompatibilityLinkControl label = null;

            if (isLabelOnly()) {
                label = CompatibilityLinkFactory.createLink(parent, SWT.NONE);
                label.getControl()
                        .setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, numColumns, 1));
            } else if (getControlDescription().getLabelPosition() == WIFormLabelPositionEnum.LEFT
                    || getControlDescription().getLabelPosition() == null) {
                label = CompatibilityLinkFactory.createLink(parent, SWT.NONE);
                createControl(parent, numColumns - 1);
            } else if (getControlDescription().getLabelPosition() == WIFormLabelPositionEnum.RIGHT) {
                createControl(parent, numColumns - 1);
                label = CompatibilityLinkFactory.createLink(parent, SWT.NONE);
            } else if (getControlDescription().getLabelPosition() == WIFormLabelPositionEnum.TOP) {
                label = CompatibilityLinkFactory.createLink(parent, SWT.NONE);
                label.getControl()
                        .setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, numColumns, 1));
                createControl(parent, numColumns);
            } else
            /* WIFormLabelPositionEnum.BOTTOM */
            {
                createControl(parent, numColumns);
                label = CompatibilityLinkFactory.createLink(parent, SWT.NONE);
                label.getControl()
                        .setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, numColumns, 1));
            }

            // Set the label and/or link-text on the control.
            if (label.isHyperlinkTextSupported() && textData.getHyperlinkText() != null) {
                label.setText(textData.getHyperlinkText());
            } else if (textData.getText() != null) {
                label.setText(textData.getText());
            }

            // Setup the selection click handler.
            label.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    /*
                     * Try to get the link (in the text field in Eclipse >= 3.1)
                     */
                    try {
                        final java.lang.reflect.Field textField = e.getClass().getField("text"); //$NON-NLS-1$
                        final String text = (String) textField.get(e);

                        if (text != null) {
                            invokeLink(((Control) e.widget).getShell(), text);
                            return;
                        }
                    } catch (final Exception failure) {
                        /* Suppress, uses backcompat */
                    }

                    selectLink(((Control) e.widget).getShell());
                }
            });

            getWorkItemEditorContextMenu().setMenuOnControl(label.getControl());

            setupToolTip(label.getControl());
        } else {
            createControl(parent, numColumns);
        }
    }

    // it's OK for subclasses to return null if there is no field for tool tip
    // support
    protected Field getFieldForToolTipSupport() {
        return null;
    }

    private void setupToolTip(final Control label) {
        /*
         * the field that provides the help text for the tool tip
         */
        final Field field = getFieldForToolTipSupport();

        /*
         * subclasses can indicate that no such tool tip functionality should
         * exist
         */
        if (field == null) {
            return;
        }

        /*
         * create a work item field change listener to set the tool tip
         */
        final ToolTipFieldChangeListener toolTipFieldChangeListener = new ToolTipFieldChangeListener(label);

        /*
         * add the listener to the field
         */
        field.addFieldChangeListener(toolTipFieldChangeListener);

        /*
         * add a dispose listener so that the field change listener is removed
         * from the work item when this UI is disposed. the work item has a
         * lifecycle independent of the UI.
         */
        label.addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(final DisposeEvent e) {
                field.removeFieldChangeListener(toolTipFieldChangeListener);
            }
        });

        /*
         * fire a "fake" field change event to the field change listener this
         * sets up the initial tool tip
         */
        final FieldChangeEvent fieldChangeEvent = new FieldChangeEvent();
        fieldChangeEvent.field = field;
        toolTipFieldChangeListener.fieldChanged(fieldChangeEvent);
    }

    private LinkTextData getLabelTextAndLinks(final WIFormControl control, final List textAndLinkList) {
        // The label attribute is used if there no link or label child.
        if (control.getLink() == null && control.getLabelText() == null) {
            return new LinkTextData(control.getLabel(), control.getLabel());
        }

        // Get the link and label from the child elements.
        final StringBuffer hyperlinkBuffer = new StringBuffer();
        final StringBuffer textBuffer = new StringBuffer();

        if (control.getLink() != null) {
            // The text for this link comes from the control attribute.
            // The URL comes from the link child.
            final String label = control.getLabel();
            if (label != null) {
                hyperlinkBuffer.append("<a>"); //$NON-NLS-1$
                hyperlinkBuffer.append(label);
                hyperlinkBuffer.append("</a>"); //$NON-NLS-1$

                textBuffer.append(label);

                textAndLinkList.add(new LabelableLinkSelectionItem(label, control.getLink()));
            }
        } else if (control.getLabelText() != null) {
            final WIFormText[] textElements = control.getLabelText().getTextElements();
            for (int i = 0; i < textElements.length; i++) {
                final WIFormText textChild = textElements[i];
                final String text = textChild.getInnerText();
                final WIFormLink link = textChild.getLink();

                if (link != null) {
                    hyperlinkBuffer.append("<a>"); //$NON-NLS-1$
                    hyperlinkBuffer.append(text);
                    hyperlinkBuffer.append("</a>"); //$NON-NLS-1$

                    textBuffer.append(text);

                    textAndLinkList.add(new LabelableLinkSelectionItem(text, link));
                } else {
                    hyperlinkBuffer.append(text);
                    textBuffer.append(text);
                }
            }
        }

        String hyperlink = hyperlinkBuffer.toString();
        String text = textBuffer.toString();

        if (text != null) {
            text = text.trim();

            if (text.length() == 0) {
                text = null;
            }
        }

        if (hyperlink != null) {
            hyperlink = hyperlink.trim();

            if (hyperlink.length() == 0) {
                hyperlink = null;
            }
        }

        if (text == null || hyperlink == null) {
            return null;
        }

        return new LinkTextData(hyperlink, text);
    }

    private void invokeLink(final Shell shell, final String clickedText) {
        LabelableLinkSelectionItem linkItem = null;

        for (final Iterator i = textAndLinkList.iterator(); i.hasNext();) {
            final LabelableLinkSelectionItem item = (LabelableLinkSelectionItem) i.next();

            if (item.getLabel().equals(clickedText)) {
                linkItem = item;
            }
        }

        if (linkItem != null && linkItem.getLink() != null) {
            invokeLink(shell, linkItem.getLink());
        }
    }

    private void selectLink(final Shell shell) {
        LabelableLinkSelectionItem linkItem = null;

        if (textAndLinkList.size() == 1) {
            linkItem = (LabelableLinkSelectionItem) textAndLinkList.get(0);
        } else if (textAndLinkList.size() > 1) {
            final LabelableLinkSelectionDialog linkDialog = new LabelableLinkSelectionDialog(shell,
                    getFormContext().getWorkItem(), (LabelableLinkSelectionItem[]) textAndLinkList
                            .toArray(new LabelableLinkSelectionItem[textAndLinkList.size()]));

            if (linkDialog.open() != IDialogConstants.OK_ID) {
                return;
            }

            linkItem = linkDialog.getSelectedLink();
        }

        if (linkItem != null) {
            invokeLink(shell, linkItem.getLink());
        }
    }

    private void invokeLink(final Shell shell, final WIFormLink link) {
        String url;
        try {
            url = link.getURL(getFormContext().getWorkItem());
            Launcher.launch(url);
        } catch (final MacroTargetNotConfiguredException macroEx) {
            MessageDialog.openInformation(shell, macroEx.getMessageTitle(), macroEx.getMessageBody());
        } catch (final Exception ex) {
            final Log log = LogFactory.getLog(LabelableControl.class);
            log.error("Could not launch the browser for link (url)", ex); //$NON-NLS-1$

            final String messageFormat = Messages.getString("LabelableControl.ErrorDialogTextFormat"); //$NON-NLS-1$
            final String message = MessageFormat.format(messageFormat, ex.getMessage());
            MessageDialog.openError(shell, Messages.getString("LabelableControl.ErrorDialogTitle"), message); //$NON-NLS-1$
        }
    }

    private static class LinkTextData {
        private final String hyperlinkText;
        private final String text;

        public LinkTextData(final String hyperlinkText, final String text) {
            this.hyperlinkText = hyperlinkText;
            this.text = text;
        }

        public String getHyperlinkText() {
            return hyperlinkText;
        }

        public String getText() {
            return text;
        }
    }
}