com.microsoft.tfs.client.common.ui.controls.vc.checkin.NotesCheckinControl.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.client.common.ui.controls.vc.checkin.NotesCheckinControl.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.controls.vc.checkin;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import com.microsoft.tfs.client.common.repository.TFSRepository;
import com.microsoft.tfs.client.common.ui.Messages;
import com.microsoft.tfs.client.common.ui.TFSCommonUIClientPlugin;
import com.microsoft.tfs.client.common.ui.controls.generic.BaseControl;
import com.microsoft.tfs.client.common.ui.framework.layout.GridDataBuilder;
import com.microsoft.tfs.client.common.ui.helpers.AutomationIDHelper;
import com.microsoft.tfs.client.common.util.ConnectionHelper;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.CheckinNote;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.CheckinNoteFieldDefinition;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.CheckinNoteFieldValue;
import com.microsoft.tfs.core.pendingcheckin.PendingCheckin;
import com.microsoft.tfs.core.pendingcheckin.events.AffectedTeamProjectsChangedEvent;
import com.microsoft.tfs.core.pendingcheckin.events.AffectedTeamProjectsChangedListener;
import com.microsoft.tfs.util.Check;
import com.microsoft.tfs.util.listeners.SingleListenerFacade;

public class NotesCheckinControl extends AbstractCheckinSubControl {
    private static final Log log = LogFactory.getLog(NotesCheckinControl.class);

    private static final String BUSY_MESSAGE = Messages.getString("NotesCheckinControl.BusyMessage"); //$NON-NLS-1$
    private static final String NO_NOTES_MESSAGE = Messages.getString("NotesCheckinControl.NoNotesMessage"); //$NON-NLS-1$
    private static final String NO_REPOSITORY_MESSAGE = Messages
            .getString("NotesCheckinControl.NoRepositoryMessage"); //$NON-NLS-1$
    private static final String NO_SAVED_NOTES_MESSAGE = Messages
            .getString("NotesCheckinControl.NoSavedNotesMessage"); //$NON-NLS-1$
    private static final String NO_SAVED_NOTES_SHELVESET_MESSAGE = Messages
            .getString("NotesCheckinControl.NoSavedNotesShelvesetMessage"); //$NON-NLS-1$

    private static final String REQUIRED_MESSAGE = Messages.getString("NotesCheckinControl.RequiredMessage"); //$NON-NLS-1$

    private static final int REQUIRED_EMPTY_COLOR = SWT.COLOR_DARK_GRAY;

    /*
     * Use a scrolled composite to hold children - this may be either a
     * composite containing the checkin notes, or a composite containing a text
     * label (loading or no notes.)
     */
    private final ScrolledComposite rootComposite;

    private final CheckinControlOptions options;

    private TFSRepository repository;
    private PendingCheckin pendingCheckin;

    private String[] projects = new String[0];
    private boolean dirty = true;
    private boolean updating = false;

    private CheckinNote checkinNote = new CheckinNote();

    private final SingleListenerFacade listeners = new SingleListenerFacade(CheckinNoteListener.class);

    private final TeamProjectsListener teamProjectsListener = new TeamProjectsListener();

    private CheckinNoteFieldControl[] fieldControls = new CheckinNoteFieldControl[0];

    protected NotesCheckinControl(final Composite parent, final int style, final CheckinControlOptions options) {
        super(parent, style, Messages.getString("NotesCheckinControl.Title"), CheckinSubControlType.CHECKIN_NOTES); //$NON-NLS-1$

        this.options = options;

        final FillLayout layout = new FillLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        setLayout(layout);

        final int rootStyle = options.isForDialog() ? SWT.BORDER : SWT.NONE;
        rootComposite = new ScrolledComposite(this, SWT.V_SCROLL | rootStyle);
        rootComposite.setLayout(new FillLayout());
        rootComposite.setExpandHorizontal(true);
        rootComposite.setExpandVertical(true);

        addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(final DisposeEvent e) {
                if (pendingCheckin != null) {
                    pendingCheckin.getPendingChanges()
                            .removeAffectedTeamProjectsChangedListener(teamProjectsListener);
                }
            }
        });
    }

    @Override
    public void addContributions(final IContributionManager contributionManager, final String groupName) {
    }

    @Override
    public void removeContributions(final IContributionManager contributionManager, final String groupname) {
    }

    public void addCheckinNoteChangedListener(final CheckinNoteListener checkinNoteListener) {
        listeners.addListener(checkinNoteListener);
    }

    public void removeCheckinNoteChangedListener(final CheckinNoteListener checkinNoteListener) {
        listeners.removeListener(checkinNoteListener);
    }

    public CheckinNote getCheckinNote() {
        return checkinNote;
    }

    public void setCheckinNote(final CheckinNote checkinNote) {
        this.checkinNote = (checkinNote != null) ? checkinNote : new CheckinNote();

        dirty = true;
        updateControls();
    }

    /**
     * Merges the values of a checkin note into this one. Used when unshelving
     * and preserving an existing checkin note.
     *
     * @param checkinNote
     */
    public void mergeCheckinNote(final CheckinNote newCheckinNote) {
        if (newCheckinNote == null || newCheckinNote.getValues() == null) {
            return;
        }

        final Map notesMap = new HashMap();

        final CheckinNoteFieldValue[] oldValues = checkinNote.getValues();
        final CheckinNoteFieldValue[] newValues = newCheckinNote.getValues();

        for (int i = 0; i < oldValues.length; i++) {
            if (oldValues[i].getValue() != null && oldValues[i].getValue().length() > 0) {
                notesMap.put(CheckinNote.canonicalizeName(oldValues[i].getName()), oldValues[i]);
            }
        }

        for (int i = 0; i < newValues.length; i++) {
            if (newValues[i].getValue() != null && newValues[i].getValue().length() > 0) {
                notesMap.put(CheckinNote.canonicalizeName(newValues[i].getName()), newValues[i]);
            }
        }

        final CheckinNoteFieldValue[] mergedValues = (CheckinNoteFieldValue[]) notesMap.values()
                .toArray(new CheckinNoteFieldValue[notesMap.values().size()]);
        checkinNote = new CheckinNote(mergedValues);

        dirty = true;
        updateControls();
    }

    public void setPendingCheckin(final TFSRepository repository, final PendingCheckin pendingCheckin) {
        if (options.getCheckinNotesReadOnly()) {
            return;
        }

        if (this.pendingCheckin != null) {
            this.pendingCheckin.getPendingChanges().removeAffectedTeamProjectsChangedListener(teamProjectsListener);
        }

        this.repository = repository;
        this.pendingCheckin = pendingCheckin;

        if (pendingCheckin != null) {
            pendingCheckin.getPendingChanges().addAffectedTeamProjectsChangedListener(teamProjectsListener);
            projects = pendingCheckin.getPendingChanges().getAffectedTeamProjectPaths();
            checkinNote = pendingCheckin.getCheckinNotes().getCheckinNotes();
        } else {
            projects = new String[0];
        }

        dirty = true;

        updateControls();
    }

    public void afterCheckin() {
        checkinNote = new CheckinNote();

        projects = pendingCheckin.getPendingChanges().getAffectedTeamProjectPaths();
        dirty = true;

        updateControls();
    }

    public void refresh() {
        dirty = true;
        updateControls();
    }

    private void updateControls() {
        if (dirty == false || updating == true) {
            return;
        }

        if (options.getCheckinNotesReadOnly() && (checkinNote == null || checkinNote.getValues().length == 0)) {
            dirty = false;
            updateEmptyControl();
            return;
        } else if (options.getCheckinNotesReadOnly()) {
            dirty = false;
            updateReadOnlyControl();
            return;
        } else if (options.getCheckinNotesHistoric()) {
            /* Set updating to true to suppress modify events */
            dirty = false;
            updating = true;
            fieldControls = updateHistoricControl();
            updating = false;
            return;
        } else if (projects == null || projects.length == 0) {
            dirty = false;
            updateEmptyControl();
            return;
        } else if (repository == null || !ConnectionHelper.isConnected(repository.getConnection())) {
            dirty = false;
            updateEmptyControl();
            return;
        }

        updateEmptyControl();

        updating = true;
        fieldControls = new CheckinNoteFieldControl[0];

        updateBusyControl();

        /*
         * Set dirty now so that we can detect if we need to (again) requery.
         * Another thread may set us dirty.
         */
        dirty = false;

        /*
         * Run a background job that queries the check-in notes for the
         * currently selected projects, and build the note fields on the UI
         * thread.
         */
        final Display display = getDisplay();

        final TFSRepository repository = this.repository;
        final String[] projects = this.projects;

        final Job updateJob = new Job(BUSY_MESSAGE) {
            @Override
            protected IStatus run(final IProgressMonitor monitor) {
                try {
                    if (projects.length == 1) {
                        log.info(MessageFormat.format("Querying checkin notes for project {0}", projects[0])); //$NON-NLS-1$
                    } else {
                        log.info("Querying checkin notes for team projects"); //$NON-NLS-1$
                    }

                    final SortedSet definitionSet = repository.getVersionControlClient()
                            .queryCheckinNoteFieldDefinitionsForServerPaths(projects);
                    final CheckinNoteFieldDefinition[] definitions = (CheckinNoteFieldDefinition[]) definitionSet
                            .toArray(new CheckinNoteFieldDefinition[definitionSet.size()]);

                    display.asyncExec(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (definitions == null || definitions.length == 0) {
                                    updateEmptyControl();
                                } else {
                                    fieldControls = updateFieldControl(definitions);
                                }

                                updateCheckinNote();
                            } finally {
                                updating = false;

                                if (dirty == true) {
                                    updateControls();
                                }
                            }
                        }
                    });
                } catch (final Exception e) {
                    return new Status(IStatus.ERROR, TFSCommonUIClientPlugin.PLUGIN_ID, 0,
                            Messages.getString("NotesCheckinControl.CouldNotQueryNotes"), //$NON-NLS-1$
                            e);
                }

                return Status.OK_STATUS;
            }
        };

        updateJob.schedule();
    }

    private void updateEmptyControl() {
        final Composite emptyControl = new Composite(rootComposite, SWT.NONE);

        final GridLayout emptyLayout = new GridLayout(1, false);
        emptyLayout.marginWidth = getHorizontalMargin();
        emptyLayout.marginHeight = getVerticalMargin();
        emptyLayout.horizontalSpacing = getHorizontalSpacing();
        emptyLayout.verticalSpacing = getVerticalSpacing();
        emptyControl.setLayout(emptyLayout);

        final Label noneLabel = new Label(emptyControl, SWT.NONE);

        if (options.getCheckinNotesReadOnly() && (checkinNote == null || checkinNote.getValues().length == 0)) {
            if (options.isForShelveset()) {
                noneLabel.setText(NO_SAVED_NOTES_SHELVESET_MESSAGE);
            } else {
                noneLabel.setText(NO_SAVED_NOTES_MESSAGE);
            }
        } else if (repository == null) {
            noneLabel.setText(NO_REPOSITORY_MESSAGE);
        } else {
            noneLabel.setText(NO_NOTES_MESSAGE);
        }

        GridDataBuilder.newInstance().hFill().vFill().applyTo(noneLabel);

        setRootCompositeContent(emptyControl);
    }

    private void updateBusyControl() {
        final Composite busyControl = new Composite(rootComposite, SWT.NONE);

        final GridLayout busyLayout = new GridLayout(1, false);
        busyLayout.marginWidth = getHorizontalMargin();
        busyLayout.marginHeight = getVerticalMargin();
        busyLayout.horizontalSpacing = getHorizontalSpacing();
        busyLayout.verticalSpacing = getVerticalSpacing();
        busyControl.setLayout(busyLayout);

        final Label busyLabel = new Label(busyControl, SWT.NONE);
        busyLabel.setText(BUSY_MESSAGE + Messages.getString("NotesCheckinControl.BusyLabelText")); //$NON-NLS-1$
        GridDataBuilder.newInstance().hFill().vFill().applyTo(busyLabel);

        setRootCompositeContent(busyControl);
    }

    private void updateReadOnlyControl() {
        final Composite noteListControl = new Composite(rootComposite, SWT.NONE);

        final GridLayout noteListLayout = new GridLayout(1, false);
        noteListLayout.marginWidth = getHorizontalMargin();
        noteListLayout.marginHeight = getVerticalMargin();
        noteListLayout.horizontalSpacing = getHorizontalSpacing();
        noteListLayout.verticalSpacing = getVerticalSpacing();
        noteListControl.setLayout(noteListLayout);

        final CheckinNoteFieldValue[] values = checkinNote.getValues();

        for (int i = 0; i < values.length; i++) {
            final Composite noteComposite = new Composite(noteListControl, SWT.NONE);

            final GridLayout noteCompositeLayout = new GridLayout(1, false);
            noteCompositeLayout.marginWidth = 0;
            noteCompositeLayout.marginHeight = 0;
            noteCompositeLayout.horizontalSpacing = 0;
            noteCompositeLayout.verticalSpacing = 0;
            noteComposite.setLayout(noteCompositeLayout);

            GridDataBuilder.newInstance().hGrab().hFill().applyTo(noteComposite);

            final String messageFormat = Messages.getString("NotesCheckinControl.NameLabelTextFormat"); //$NON-NLS-1$
            final String message = MessageFormat.format(messageFormat, values[i].getName());

            final Label nameLabel = new Label(noteComposite, SWT.NONE);
            nameLabel.setText(message);
            GridDataBuilder.newInstance().hGrab().hFill().applyTo(nameLabel);

            final Text valueText = new Text(noteComposite, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.READ_ONLY);
            valueText.setText(values[i].getValue());
            GridDataBuilder.newInstance().hGrab().hFill().applyTo(valueText);
        }

        setRootCompositeContent(noteListControl);
        rootComposite.setMinHeight(noteListControl.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
    }

    private CheckinNoteFieldControl[] updateHistoricControl() {
        final Composite noteListControl = new Composite(rootComposite, SWT.NONE);

        final GridLayout noteListLayout = new GridLayout(1, false);
        noteListLayout.marginWidth = getHorizontalMargin();
        noteListLayout.marginHeight = getVerticalMargin();
        noteListLayout.horizontalSpacing = getHorizontalSpacing();
        noteListLayout.verticalSpacing = getVerticalSpacing();
        noteListControl.setLayout(noteListLayout);

        final CheckinNoteFieldValue[] currentValues = checkinNote.getValues();

        fieldControls = new CheckinNoteFieldControl[currentValues.length];

        for (int i = 0; i < currentValues.length; i++) {
            fieldControls[i] = new CheckinNoteFieldControl(noteListControl, SWT.MULTI | SWT.WRAP);
            fieldControls[i].setName(currentValues[i].getName());
            fieldControls[i].setText(currentValues[i].getValue());

            GridDataBuilder.newInstance().hFill().hGrab().applyTo(fieldControls[i]);
        }

        setRootCompositeContent(noteListControl);
        rootComposite.setMinHeight(noteListControl.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

        return fieldControls;
    }

    private CheckinNoteFieldControl[] updateFieldControl(final CheckinNoteFieldDefinition[] definitions) {
        final Composite noteListControl = new Composite(rootComposite, SWT.NONE);

        final GridLayout noteListLayout = new GridLayout(1, false);
        noteListLayout.marginWidth = getHorizontalMargin();
        noteListLayout.marginHeight = getVerticalMargin();
        noteListLayout.horizontalSpacing = getHorizontalSpacing();
        noteListLayout.verticalSpacing = getVerticalSpacing();
        noteListControl.setLayout(noteListLayout);

        fieldControls = new CheckinNoteFieldControl[definitions.length];

        final CheckinNoteFieldValue[] currentValues = checkinNote.getValues();

        for (int i = 0; i < definitions.length; i++) {
            fieldControls[i] = new CheckinNoteFieldControl(noteListControl, SWT.MULTI | SWT.WRAP);
            fieldControls[i].setCheckinNoteFieldDefinition(definitions[i]);
            fieldControls[i].setAutomationID(definitions[i].getName());

            /* Restore previously entered data */
            for (int j = 0; j < currentValues.length; j++) {
                if (CheckinNote.canonicalizeName(currentValues[j].getName())
                        .equals(CheckinNote.canonicalizeName(definitions[i].getName()))) {
                    fieldControls[i].setText(currentValues[j].getValue());
                    break;
                }
            }

            GridDataBuilder.newInstance().hFill().hGrab().applyTo(fieldControls[i]);
        }

        setRootCompositeContent(noteListControl);
        rootComposite.setMinHeight(noteListControl.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

        return fieldControls;
    }

    /**
     * Sets new content on {@link #rootComposite}, disposing of old content.
     */
    private void setRootCompositeContent(final Control newContent) {
        final Control oldContent = rootComposite.getContent();

        rootComposite.setContent(newContent);

        if (oldContent != null && !oldContent.isDisposed()) {
            oldContent.dispose();
        }
    }

    private class TeamProjectsListener implements AffectedTeamProjectsChangedListener {
        @Override
        public void onAffectedTeamProjectsChanged(final AffectedTeamProjectsChangedEvent e) {
            final Runnable updater = new Runnable() {
                @Override
                public void run() {
                    final String[] oldProjects = projects;
                    projects = e.getNewTeamProjects();

                    dirty = !Arrays.equals(projects, oldProjects);

                    if (dirty) {
                        updateControls();
                    }
                }
            };

            /*
             * TODO: is this necessary? i think this event is always fired on
             * the ui thread.
             */
            if (getDisplay().getThread() != Thread.currentThread()) {
                getDisplay().asyncExec(updater);
            } else {
                updater.run();
            }
        }
    }

    /*
     * update the internal checkin note with the user's input
     */
    private void updateCheckinNote() {
        if (fieldControls == null || fieldControls.length == 0) {
            checkinNote = new CheckinNote();
        } else {
            final CheckinNoteFieldValue[] values = new CheckinNoteFieldValue[fieldControls.length];

            for (int i = 0; i < fieldControls.length; i++) {
                values[i] = fieldControls[i].getCheckinNoteFieldValue();
            }

            checkinNote = new CheckinNote(values);
        }

        ((CheckinNoteListener) listeners.getListener()).onCheckinNoteChanged(new CheckinNoteEvent(this));
    }

    private class CheckinNoteFieldControl extends BaseControl {
        private final int style;

        private CheckinNoteFieldDefinition definition;
        private String name;

        private final Label nameLabel;
        private final Text valueText;

        public CheckinNoteFieldControl(final Composite parent, final int style) {
            super(parent, SWT.NONE);

            this.style = style;

            final GridLayout layout = new GridLayout(1, false);
            layout.marginWidth = 0;
            layout.marginHeight = 0;
            layout.horizontalSpacing = 0;
            layout.verticalSpacing = 0;
            setLayout(layout);

            nameLabel = new Label(this, SWT.NONE);
            GridDataBuilder.newInstance().hFill().hGrab().applyTo(nameLabel);

            valueText = new Text(this, SWT.BORDER | SWT.WRAP | SWT.MULTI | (style & (SWT.READ_ONLY)));

            /*
             * MSFT displays "<Required>" in empty required fields. Do this
             * until the control gets focus.
             */
            valueText.addFocusListener(new FocusListener() {
                @Override
                public void focusGained(final FocusEvent e) {
                    if (definition != null && definition.isRequired() && valueText.getData("empty") != null) //$NON-NLS-1$
                    {
                        valueText.setData("empty", null); //$NON-NLS-1$
                        valueText.setText(""); //$NON-NLS-1$
                        valueText.setForeground(getDisplay().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND));
                    }
                }

                @Override
                public void focusLost(final FocusEvent e) {
                    if (definition != null && definition.isRequired() && valueText.getText().trim().length() == 0) {
                        valueText.setData("empty", Boolean.TRUE); //$NON-NLS-1$
                        valueText.setText(REQUIRED_MESSAGE);
                        valueText.setForeground(getDisplay().getSystemColor(REQUIRED_EMPTY_COLOR));
                    }
                }
            });

            /*
             * Allow tab keys to traverse to the next fields.
             */
            valueText.addTraverseListener(new TraverseListener() {
                @Override
                public void keyTraversed(final TraverseEvent e) {
                    if (e.detail == SWT.TRAVERSE_TAB_NEXT || e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
                        e.doit = true;
                    }
                }
            });

            /*
             * We want to relayout the parent on modify events so that we can
             * dynamically grow the text box.
             */
            valueText.addModifyListener(new ModifyListener() {
                @Override
                public void modifyText(final ModifyEvent e) {
                    if (rootComposite.getContent() != null && !rootComposite.getContent().isDisposed()) {
                        ((Composite) rootComposite.getContent()).layout(true);
                        rootComposite
                                .setMinHeight(rootComposite.getContent().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
                        rootComposite.layout(true);
                    }

                    if (!updating) {
                        updateCheckinNote();
                    }
                }
            });

            GridDataBuilder.newInstance().hFill().hGrab().applyTo(valueText);
        }

        public void setName(final String name) {
            this.name = name;

            final String messageFormat = Messages.getString("NotesCheckinControl.NameLabelTextFormat"); //$NON-NLS-1$
            final String message = MessageFormat.format(messageFormat, name);
            nameLabel.setText(message);

        }

        public void setAutomationID(final String automationId) {
            AutomationIDHelper.setWidgetID(valueText, automationId);
        }

        public void setCheckinNoteFieldDefinition(final CheckinNoteFieldDefinition definition) {
            Check.notNull(definition, "definition"); //$NON-NLS-1$

            this.definition = definition;

            final String messageFormat = Messages.getString("NotesCheckinControl.NameLabelTextFormat"); //$NON-NLS-1$
            final String message = MessageFormat.format(messageFormat, definition.getName());
            nameLabel.setText(message);

            if (definition.isRequired() && (style & SWT.READ_ONLY) == 0) {
                valueText.setBackground(getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
                valueText.setForeground(getDisplay().getSystemColor(REQUIRED_EMPTY_COLOR));
                valueText.setData("empty", Boolean.TRUE); //$NON-NLS-1$
                valueText.setText(REQUIRED_MESSAGE);
            }
        }

        public void setText(final String text) {
            Check.notNull(text, "text"); //$NON-NLS-1$

            if (definition != null && definition.isRequired() && text.trim().length() == 0) {
                valueText.setData("empty", Boolean.TRUE); //$NON-NLS-1$
                valueText.setForeground(getDisplay().getSystemColor(REQUIRED_EMPTY_COLOR));
                valueText.setText(REQUIRED_MESSAGE);
            } else if (definition != null && definition.isRequired()) {
                valueText.setData("empty", null); //$NON-NLS-1$
                valueText.setForeground(getDisplay().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND));
                valueText.setText(text);
            } else {
                valueText.setData("empty", Boolean.FALSE); //$NON-NLS-1$
                valueText.setText(text);
            }
        }

        public String getText() {
            if (valueText.getData("empty") != null) //$NON-NLS-1$
            {
                final Boolean empty = (Boolean) valueText.getData("empty"); //$NON-NLS-1$

                if (Boolean.TRUE.equals(empty)) {
                    return ""; //$NON-NLS-1$
                }
            }

            return valueText.getText().trim();
        }

        public CheckinNoteFieldValue getCheckinNoteFieldValue() {
            if (definition != null) {
                return new CheckinNoteFieldValue(definition.getName(), getText());
            } else if (name != null) {
                return new CheckinNoteFieldValue(name, getText());
            } else {
                throw new NullPointerException(
                        Messages.getString("NotesCheckinControl.NoteFieldNotConfiguredWithName")); //$NON-NLS-1$
            }
        }
    }

    public interface CheckinNoteListener {
        public void onCheckinNoteChanged(CheckinNoteEvent e);
    }

    public class CheckinNoteEvent {
        private final NotesCheckinControl control;

        public CheckinNoteEvent(final NotesCheckinControl notesCheckinControl) {
            control = notesCheckinControl;
        }

        public NotesCheckinControl getControl() {
            return control;
        }
    }
}