org.LexGrid.LexBIG.gui.displayResults.VDDisplayCodedNodeSet.java Source code

Java tutorial

Introduction

Here is the source code for org.LexGrid.LexBIG.gui.displayResults.VDDisplayCodedNodeSet.java

Source

/*
 * Copyright: (c) 2004-2010 Mayo Foundation for Medical Education and 
 * Research (MFMER). All rights reserved. MAYO, MAYO CLINIC, and the
 * triple-shield Mayo logo are trademarks and service marks of MFMER.
 *
 * Except as contained in the copyright notice above, or as used to identify 
 * MFMER as the author of this software, the trade names, trademarks, service
 * marks, or product names of the copyright holder shall not be used in
 * advertising, promotion or otherwise in connection with this software without
 * prior written authorization of the copyright holder.
 * 
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 *       http://www.eclipse.org/legal/epl-v10.html
 * 
 */
package org.LexGrid.LexBIG.gui.displayResults;

import java.util.ArrayList;
import java.util.HashSet;

import org.LexGrid.LexBIG.DataModel.Collections.AssociationList;
import org.LexGrid.LexBIG.DataModel.Collections.NameAndValueList;
import org.LexGrid.LexBIG.DataModel.Collections.ResolvedConceptReferenceList;
import org.LexGrid.LexBIG.DataModel.Collections.SortOptionList;
import org.LexGrid.LexBIG.DataModel.Core.AssociatedConcept;
import org.LexGrid.LexBIG.DataModel.Core.Association;
import org.LexGrid.LexBIG.DataModel.Core.CodingSchemeVersionOrTag;
import org.LexGrid.LexBIG.DataModel.Core.ConceptReference;
import org.LexGrid.LexBIG.DataModel.Core.NameAndValue;
import org.LexGrid.LexBIG.DataModel.Core.ResolvedConceptReference;
import org.LexGrid.LexBIG.Exceptions.LBException;
import org.LexGrid.LexBIG.Exceptions.LBParameterException;
import org.LexGrid.LexBIG.Exceptions.LBResourceUnavailableException;
import org.LexGrid.LexBIG.Impl.LexBIGServiceImpl;
import org.LexGrid.LexBIG.LexBIGService.CodedNodeGraph;
import org.LexGrid.LexBIG.LexBIGService.CodedNodeSet;
import org.LexGrid.LexBIG.LexBIGService.LexBIGService;
import org.LexGrid.LexBIG.Utility.Constructors;
import org.LexGrid.LexBIG.Utility.Iterators.ResolvedConceptReferencesIterator;
import org.LexGrid.LexBIG.gui.DialogHandler;
import org.LexGrid.LexBIG.gui.LB_VSD_GUI;
import org.LexGrid.LexBIG.gui.Utility;
import org.LexGrid.LexBIG.gui.plugin.PluginRetriever;
import org.LexGrid.LexBIG.gui.plugin.TabbedContent;
import org.LexGrid.codingSchemes.CodingScheme;
import org.LexGrid.commonTypes.Property;
import org.LexGrid.commonTypes.PropertyQualifier;
import org.LexGrid.commonTypes.Source;
import org.LexGrid.concepts.Comment;
import org.LexGrid.concepts.Definition;
import org.LexGrid.concepts.Entity;
import org.LexGrid.concepts.Presentation;
import org.LexGrid.concepts.PropertyLink;
import org.LexGrid.relations.Relations;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import prefuse.Constants;
import prefuse.data.Node;

/**
 * This class displays the results of a CodedNodeSet query in a shell.
 * 
 * @author <A HREF="mailto:johnson.thomas@mayo.edu">Thomas Johnson</A>
 * @author <A HREF="mailto:leisch.jason@mayo.edu">Jason Leisch</A>
 * @version subversion $Revision: $ checked in on $Date: $
 */
public class VDDisplayCodedNodeSet {
    private static Logger log = Logger.getLogger("LexBIG.GUI");
    private LB_VSD_GUI lb_gui_;
    private DialogHandler dialog_;
    private Shell shell_;
    private LBException resolveException_;
    private ProgressBar progressBar_;
    private Composite resultsComposite_;
    private StackLayout stack_;
    private ResolvedConceptReferencesIterator codeIterator_;
    private ResolvedConceptReference[] graphRcr_;
    private ArrayList<ResolvedConceptReference> displayedResults_;
    private HashSet<String> displayedResultsCodes_;
    private Table displayedCodeList_;
    private static String FETCHING_MORE = "Getting Results...";
    private int fetchSize = 50;
    private StyledText codeDetails_;
    private Label busyResolvingLabel_;
    private Button showSecondaryRel_button;
    private boolean showSecondaryRel_selected = false;
    private Button showCodes_button;
    private boolean showCodes_selected = true;
    private boolean graphMode_ = false;
    private VDGraphView primaryGraph;
    private ConceptTreeView primaryTree;
    private final boolean twoGraphs;
    private TabFolder tabs;

    /*
     * The subsetGraph/Tree are used only in the Coded Node Graph case (ie, not
     * the "Coded Node Set" case). They will show the coded node set, so that
     * the Coded Node Graph shows all 4 views.
     */
    private VDGraphView secondaryGraph;
    private ConceptTreeView secondaryTree;
    private Object currentControl;

    public VDDisplayCodedNodeSet(LB_VSD_GUI lb_gui, CodedNodeGraph cng, SortOptionList sortOptions,
            boolean flatDisplay, boolean resolveForward, boolean resolveBackward, int resolveDepth, int maxToReturn,
            ConceptReference graphFocus) {
        this.twoGraphs = !flatDisplay;
        preInit(lb_gui);

        resolveGraph(cng, sortOptions, flatDisplay, resolveForward, resolveBackward, resolveDepth, maxToReturn,
                graphFocus);
    }

    public VDDisplayCodedNodeSet(LB_VSD_GUI lb_gui, CodedNodeSet cns, SortOptionList sortOptions) {
        this.twoGraphs = false;
        preInit(lb_gui);

        resolveCodeSet(cns, sortOptions);

    }

    private void preInit(LB_VSD_GUI lb_gui) {
        lb_gui_ = lb_gui;
        shell_ = new Shell(lb_gui_.getShell().getDisplay());
        shell_.setSize(640, 480);

        dialog_ = new DialogHandler(shell_);

        shell_.setText("Result Browser");

        init();

        shell_.open();

        shell_.addShellListener(new ShellAdapter() {
            public void shellClosed(ShellEvent arg0) {
                if (codeIterator_ != null) {
                    try {
                        codeIterator_.release();
                    } catch (LBResourceUnavailableException e) {
                        // do nothing.
                    }
                    codeIterator_ = null;
                }
            }
        });

        shell_.getDisplay().addFilter(SWT.KeyUp, new Listener() {

            public void handleEvent(Event event) {
                GraphView currentGraph;
                if (currentControl == null || !(currentControl instanceof GraphView)) {
                    return;
                }
                currentGraph = (GraphView) currentControl;
                if (event.stateMask == SWT.CTRL) {
                    // CTRL 1 through 4
                    if (event.keyCode == 49) {
                        currentGraph.updateOrientation(Constants.ORIENT_LEFT_RIGHT);
                    } else if (event.keyCode == 50) {
                        currentGraph.updateOrientation(Constants.ORIENT_TOP_BOTTOM);
                    } else if (event.keyCode == 51) {
                        currentGraph.updateOrientation(Constants.ORIENT_RIGHT_LEFT);
                    } else if (event.keyCode == 52) {
                        currentGraph.updateOrientation(Constants.ORIENT_BOTTOM_TOP);
                    } else if (event.keyCode == 61) {
                        // ctrl +
                        currentGraph.increaseSpace();
                    } else if (event.keyCode == 45) {
                        // ctrl -
                        currentGraph.decreaseSpace();
                    }
                }
            }

        });

        shell_.setImage(new Image(shell_.getDisplay(), this.getClass().getResourceAsStream("/icons/result.gif")));
    }

    private void init() {
        stack_ = new StackLayout();
        shell_.setLayout(stack_);

        // create the *busy* windows - only displays while we do the initial
        // resolve.
        Composite busyComposite = new Composite(shell_, SWT.NONE);
        busyComposite.setLayout(new GridLayout(1, false));

        busyResolvingLabel_ = Utility.makeWrappingLabel(busyComposite, "Resolving the Code Set", 1);
        busyResolvingLabel_.setLayoutData(
                new GridData(GridData.VERTICAL_ALIGN_END | GridData.HORIZONTAL_ALIGN_CENTER | GridData.FILL_BOTH));

        progressBar_ = new ProgressBar(busyComposite, SWT.INDETERMINATE);
        progressBar_.setLayoutData(new GridData(
                GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING | GridData.GRAB_VERTICAL));

        // create the results window.

        resultsComposite_ = new Composite(shell_, SWT.NONE);
        resultsComposite_.setLayout(new GridLayout(1, false));

        SashForm leftRight = new SashForm(resultsComposite_, SWT.HORIZONTAL);
        leftRight.SASH_WIDTH = 5;

        leftRight.setVisible(true);
        leftRight.setLayout(new GridLayout(1, false));
        leftRight.setLayoutData(new GridData(GridData.FILL_BOTH));

        displayedCodeList_ = new Table(leftRight, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        displayedCodeList_.setLayoutData(new GridData(GridData.FILL_BOTH));
        displayedCodeList_.addSelectionListener(codeListSelectionListener);

        // Right-hand controls ...
        // The panels on the right side will be "sash"-ed as well, to allow for
        // optimal viewing of the graph with lower resolutions
        SashForm rightTopBottom = new SashForm(leftRight, SWT.VERTICAL);

        rightTopBottom.setLayoutData(new GridData(GridData.FILL_BOTH));
        rightTopBottom.setLayout(new GridLayout());

        // Add html-capable form for display of selected item details ...
        codeDetails_ = new StyledText(rightTopBottom,
                SWT.WRAP | SWT.BORDER | SWT.MULTI | SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL);

        /*
         * In the lower right corner is a tabbed form with two tabs, along with
         * two checkboxes.
         * 
         * The first tab is the graph view. The 2nd tab is the new tree view.
         */
        Composite lowerRight = new Composite(rightTopBottom, SWT.NONE);
        lowerRight.setLayout(new GridLayout(1, false));

        buildTabFolder(lowerRight);
        buildBottomTabs(tabs);
        addUserTabs();

        // Add checkboxes ...
        Composite graphChoices = new Composite(lowerRight, SWT.NONE);
        graphChoices.setLayout(new GridLayout(1, false));
        graphChoices.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        showCodes_button = new Button(graphChoices, SWT.CHECK);
        showCodes_button.setText("Show &codes");
        showCodes_button.setSelection(showCodes_selected);
        showCodes_button.addSelectionListener(graphingCheckboxListener);

        showSecondaryRel_button = new Button(graphChoices, SWT.CHECK);
        showSecondaryRel_button.setText("Show non-hierarchical &relations (graph only)");
        showSecondaryRel_button.setSelection(showSecondaryRel_selected);
        showSecondaryRel_button.addSelectionListener(graphingCheckboxListener);

        // Add graph viewer ...
        // Graph graph = new Graph(true);
        // graph.addNode();

        leftRight.setWeights(new int[] { 30, 70 });
        rightTopBottom.setWeights(new int[] { 30, 70 });
        stack_.topControl = busyComposite;
    }

    private void addUserTabs() {
        PluginRetriever pr = new PluginRetriever();
        TabbedContent[] plugins = pr.getTabbedContentPlugins();
        for (TabbedContent tc : plugins) {
            try {
                addContentTab(tc);
            } catch (Exception e) {
                log.error("Unexpected Error from plugin during initialization", e);
            }
        }
    }

    private void buildTabFolder(final Composite parentComposite) {
        tabs = new TabFolder(parentComposite, SWT.TOP);
        tabs.addSelectionListener(new SelectionListener() {
            public void widgetDefaultSelected(SelectionEvent e) {
            }

            public void widgetSelected(SelectionEvent e) {
                currentControl = tabs.getItem(tabs.getSelectionIndex()).getData();
            }
        });
        tabs.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL));
    }

    public TabItem addContentTab(TabbedContent control) {
        control.setParentComposite(tabs);
        TabItem newTab = new TabItem(tabs, SWT.NONE);
        newTab.setData(control);
        newTab.setText(control.getTabName());
        newTab.setControl(control.getControl());
        return newTab;
    }

    private void buildBottomTabs(final TabFolder tabFolder) {

        primaryGraph = new VDGraphView(tabFolder, VDDisplayCodedNodeSet.this);
        TabItem primaryGraphTab = new TabItem(tabFolder, SWT.NONE);
        primaryGraphTab.setText("Association Graph");
        primaryGraphTab.setControl(primaryGraph.getSwtComposite());
        primaryGraphTab.setData(primaryGraph);

        TabItem primaryTreeTab = new TabItem(tabFolder, SWT.NONE);
        primaryTreeTab.setText("Association Tree");
        primaryTree = new ConceptTreeView(shell_, tabFolder);
        primaryTreeTab.setControl(primaryTree.getTree());
        primaryTree.addSelectionListener(new TreeSelectionListener());

        currentControl = primaryGraph;

        if (twoGraphs) {
            secondaryGraph = new VDGraphView(tabFolder, VDDisplayCodedNodeSet.this);
            TabItem secondaryGraphTab = new TabItem(tabFolder, SWT.NONE);
            secondaryGraphTab.setData(secondaryGraph);
            secondaryGraphTab.setText("Subset Graph");
            secondaryGraphTab.setControl(secondaryGraph.getSwtComposite());
            TabItem secondaryTreeTab = new TabItem(tabFolder, SWT.NONE);
            secondaryTreeTab.setText("Subset Tree");
            secondaryTree = new ConceptTreeView(shell_, tabFolder);
            secondaryTreeTab.setControl(secondaryTree.getTree());
            secondaryTree.addSelectionListener(new TreeSelectionListener());
        }
    }

    /**
     * A SelectionListener to handle the the selection of elements in the tree.
     * When something is selected in the tree, update the corresponding graphs
     * to focus to (if the full graph) the matching node, or to re-root with (if
     * the subsetted graph) the matching node.
     * 
     * Also update the concept list to highlight the matching concept in blue.
     * 
     */
    private class TreeSelectionListener implements SelectionListener {
        public void widgetDefaultSelected(SelectionEvent e) {
            Tree t = (Tree) e.getSource();
            TreeItem ti = t.getSelection()[0];
            if (ti == null) {
                return;
            }
            Object o = ti.getData();
            if (!(o instanceof ResolvedConceptReference)) {
                return;
            }
            ResolvedConceptReference rcr = (ResolvedConceptReference) o;
            displayConceptDetails(rcr);
            updateGraphForConceptSelection(rcr);
            addOrUpdateDisplayedResults(rcr, -1, SWT.COLOR_BLUE, -1, -1, SWT.COLOR_BLUE, -1, false);

        }

        public void widgetSelected(SelectionEvent e) {
        }
    }

    /**
     * A selection listener to handle: - the display of secondary relations -
     * the display of codes on concepts
     */
    private final SelectionListener graphingCheckboxListener = new SelectionListener() {
        public void widgetSelected(SelectionEvent e) {
            if (e.getSource() == showSecondaryRel_button) {
                shell_.getDisplay().syncExec(new Runnable() {
                    public void run() {
                        showSecondaryRel_selected = showSecondaryRel_button.getSelection();
                        primaryGraph.m_vis.run("filter");
                        if (twoGraphs) {
                            secondaryGraph.m_vis.run("filter");
                        }
                    }
                });
            } else if (e.getSource() == showCodes_button) {
                shell_.getDisplay().syncExec(new Runnable() {
                    public void run() {
                        showCodes_selected = showCodes_button.getSelection();
                        primaryGraph.getGraph().refreshNodeNames(showCodes_selected, showSecondaryRel_selected);
                        primaryGraph.m_vis.run("filter");
                        primaryTree.setCodesShown(showCodes_selected);
                        if (twoGraphs) {
                            secondaryGraph.getGraph().refreshNodeNames(showCodes_selected,
                                    showSecondaryRel_selected);
                            secondaryGraph.m_vis.run("filter");
                            secondaryTree.setCodesShown(showCodes_selected);
                        }
                    }
                });
            }
        }

        public void widgetDefaultSelected(SelectionEvent e) {
        }
    };

    private final SelectionListener codeListSelectionListener = new SelectionListener() {
        public void widgetDefaultSelected(SelectionEvent e) {
        }

        public void widgetSelected(SelectionEvent e) {
            int index = displayedCodeList_.getSelectionIndex();
            if (index == -1) {
                return;
            }
            if (index == displayedResults_.size()) {
                if (displayedCodeList_.getItem(index).equals(FETCHING_MORE)) {
                    // in the process of fetching more... do nothing.
                } else {
                    // this means that they clicked on the "fetch more results"
                    // item.
                    TableItem ti = displayedCodeList_.getItem(index);
                    ti.setText(FETCHING_MORE);
                    resolveMoreResults();
                }
                codeDetails_.setText("More results are being retrieved.");

            } else {
                ResolvedConceptReference rcr = displayedResults_.get(index);
                displayConceptDetails(rcr);
                updateTreeForConceptSelection(rcr);
                updateGraphForConceptSelection(rcr);
                addOrUpdateDisplayedResults(rcr, -1, SWT.COLOR_BLUE, -1, -1, SWT.COLOR_BLUE, -1, false);
                TabItem[] userTabs = tabs.getItems();
                for (TabItem userTab : userTabs) {
                    Object c = userTab.getData();
                    if (c instanceof TabbedContent) {
                        TabbedContent tc = (TabbedContent) c;
                        try {
                            tc.conceptSelected(rcr);
                        } catch (Exception ex) {
                            log.error("Unexpected Error from plugin during conceptSelected", ex);
                        }
                    }
                }
            }
        }
    };

    private void updateTreeForConceptSelection(ResolvedConceptReference rcr) {
        if (!graphMode_) {
            return;
        }
        primaryTree.updateTreeForConceptSelection(rcr);
    }

    private void resolveCodeSet(CodedNodeSet cns, SortOptionList sortOptions) {
        Resolver resolver = new Resolver(cns, this, sortOptions);

        shell_.setCursor(shell_.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));

        new Thread(resolver).start();
    }

    private void resolveGraph(CodedNodeGraph cng, SortOptionList sortOptions, boolean flat, boolean forward,
            boolean backward, int depth, int maxToReturn, ConceptReference focus) {
        GraphResolver resolver = new GraphResolver(cng, this, sortOptions, flat, forward, backward, depth,
                maxToReturn, focus);

        shell_.setCursor(shell_.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));

        new Thread(resolver).start();
    }

    protected void displayConceptDetails(ResolvedConceptReference rcr) {
        try {
            final StringBuffer text = new StringBuffer();
            text.append(
                    "<b>Coding Scheme:</b> " + rcr.getCodingSchemeName() + " - " + rcr.getCodingSchemeURI() + "\n");
            text.append("<b>Entity Code:</b> " + rcr.getConceptCode() + "\n");
            Entity node = rcr.getEntity();
            if (node != null) {
                fieldHelper(text, node.getEntityCodeNamespace(), "Entity Code Namespace");
            }
            if (rcr.getEntityDescription() != null && rcr.getEntityDescription().getContent() != null
                    && rcr.getEntityDescription().getContent().length() > 0) {
                text.append("<b>Entity Description:</b> " + rcr.getEntityDescription().getContent() + "\n");
            }
            if (node != null) {
                for (String entityType : node.getEntityType()) {
                    fieldHelper(text, entityType, "Entity Type");
                }

                if (node.getOwner() != null)
                    fieldHelper(text, node.getOwner(), "Owner");

                fieldHelper(text, node.getStatus(), "Status");
                fieldHelper(text, node.getIsActive(), "Is Active");
                fieldHelper(text, node.getIsAnonymous(), "Is Anonymous");

                if (node.getEffectiveDate() != null)
                    fieldHelper(text, node.getEffectiveDate().toString(), "Effective Date");

                if (node.getExpirationDate() != null)
                    fieldHelper(text, node.getExpirationDate().toString(), "Expiration Date");

                Presentation[] p = node.getPresentation();
                presentationPrinter(p, text);

                Definition[] d = node.getDefinition();
                presentationPrinter(d, text);

                Property[] pr = node.getProperty();
                presentationPrinter(pr, text);

                PropertyLink[] pl = node.getPropertyLink();
                if (pl != null) {
                    for (int i = 0; i < pl.length; i++) {

                        fieldHelper(text, pl[i].getPropertyLink(), "Property Link");
                        fieldHelper(text, pl[i].getSourceProperty(), "   Source Property");
                        fieldHelper(text, pl[i].getTargetProperty(), "   Target Property");
                    }
                }

                Comment[] c = node.getComment();
                presentationPrinter(c, text);

            }

            shell_.getDisplay().syncExec(new Runnable() {
                public void run() {
                    TextContent tc = new TextContent(shell_.getDisplay());
                    tc.setContent(text.toString());
                    codeDetails_.setText(tc.toPlainText());
                    codeDetails_.setStyleRanges(tc.getStyleRanges());
                }
            });

        } catch (RuntimeException e) {
            log.error("Unexpected Error", e);
            shell_.getDisplay().syncExec(new Runnable() {
                public void run() {
                    codeDetails_.setText("Sorry, and unexpected error occurred.  See the log for details.");
                }
            });

        }
    }

    private void presentationPrinter(Property[] p, StringBuffer text) {
        if (p != null) {
            for (int i = 0; i < p.length; i++) {
                if (p[i].getValue() != null) {
                    fieldHelper(text, p[i].getValue().getContent(), p[i].getClass().getSimpleName());
                    fieldHelper(text, p[i].getPropertyName(), "   Property Name");
                    fieldHelper(text, p[i].getPropertyId(), "   Property Id");
                    fieldHelper(text, p[i].getLanguage(), "   Language");

                    if (p[i] instanceof Presentation) {
                        Presentation presentation = (Presentation) p[i];
                        fieldHelper(text, presentation.getIsPreferred(), "   Is Preferred");
                        fieldHelper(text, presentation.getDegreeOfFidelity(), "   Degree Of Fidelity");
                        fieldHelper(text, presentation.getMatchIfNoContext(), "   Match If No Context");
                        fieldHelper(text, presentation.getRepresentationalForm(), "   Representational Form");
                    } else if (p[i] instanceof Definition) {
                        Definition definition = (Definition) p[i];
                        fieldHelper(text, definition.getIsPreferred(), "   Is Preferred");

                    }

                    Source[] s = p[i].getSource();
                    if (s != null) {
                        for (int j = 0; j < s.length; j++) {
                            fieldHelper(text, s[j].getContent() + " , <b>Role:</b> " + s[j].getRole()
                                    + ", <b>SubRef:</b> " + s[j].getSubRef(), "   Source");
                        }
                    }

                    String[] uc = p[i].getUsageContext();
                    if (uc != null) {
                        for (int j = 0; j < uc.length; j++) {
                            fieldHelper(text, uc[j], "   Usage Content");
                        }
                    }
                    PropertyQualifier[] pq = p[i].getPropertyQualifier();
                    if (pq != null) {
                        for (int j = 0; j < pq.length; j++) {
                            fieldHelper(text, pq[j].getPropertyQualifierName()
                                    + " , <b>Property Qualifier Content:</b> " + pq[j].getValue().getContent(),
                                    "   Property Qualifier Id");
                        }
                    }

                }
            }
        }
    }

    private UpdateSelectionGraphResolver usgr_;

    private void updateGraphForConceptSelection(final ResolvedConceptReference rcr) {
        try {
            if (graphMode_) {
                primaryGraph.focusCode(rcr.getConceptCode(),
                        (rcr.getEntityDescription() == null ? "" : rcr.getEntityDescription().getContent()));

                shell_.getDisplay().asyncExec(new Runnable() {
                    public void run() {
                        primaryTree.updateTreeForConceptSelection(rcr);
                    }
                });
                /*
                 * Added for coded node set within the coded node graph
                 */
                Graph temp = new Graph(true);

                temp.addNode("resolving relationships, please wait.");
                secondaryGraph.setGraph(temp);

                if (usgr_ != null) {
                    usgr_.stop = true;
                }
                usgr_ = new UpdateSelectionGraphResolver(rcr, secondaryGraph, secondaryTree);
                Thread resolve = new Thread(usgr_);
                resolve.start();
            } else {
                Graph temp = new Graph(true);

                temp.addNode("resolving relationships, please wait.");
                primaryGraph.setGraph(temp);

                if (usgr_ != null) {
                    usgr_.stop = true;
                }
                usgr_ = new UpdateSelectionGraphResolver(rcr, primaryGraph, primaryTree);
                Thread resolve = new Thread(usgr_);
                resolve.start();

            }
        } catch (Exception e) {
            log.error("Unexpected Error", e);
        }
    }

    private void fieldHelper(StringBuffer text, String field, String fieldName) {
        if (field != null && field.length() > 0) {
            text.append("<b>" + fieldName + ":</b> " + field + "\n");
        }
    }

    private void fieldHelper(StringBuffer text, Boolean field, String fieldName) {
        if (field != null) {
            text.append("<b>" + fieldName + ":</b> " + field.toString() + "\n");
        }
    }

    private void resolveMoreResults() {
        new Thread(new ResolveMore()).start();
    }

    private void resolveFinished(final boolean forward) {
        shell_.getDisplay().syncExec(new Runnable() {
            public void run() {
                try {
                    if (resolveException_ != null) {
                        throw resolveException_;
                    }

                    ResolvedConceptReference[] codes = null;
                    if (graphRcr_ != null) {
                        // had a graph resolution
                        graphMode_ = true;
                        codes = graphRcr_;
                    } else {
                        graphMode_ = false;
                        codes = codeIterator_.next(fetchSize).getResolvedConceptReference();
                    }
                    displayedResults_ = new ArrayList<ResolvedConceptReference>();
                    displayedResultsCodes_ = new HashSet<String>();
                    Graph graph = null;
                    Node top = null;

                    if (graphMode_) {
                        primaryTree.addConcepts(codes);
                        graph = new Graph(true);
                        if (codes.length > 1) {
                            // if there is more than one code at the top level,
                            // automatically add
                            // the '@' (ultimate root) or '@@' (ultimate end)
                            // node in the graph view.
                            top = graph.addNode(forward ? "@" : "@@");
                        }
                    }

                    for (int i = 0; i < codes.length; i++) {
                        addCodeToDisplayedResults(codes[i]);
                        Node temp = null;
                        if (graph != null) {
                            temp = graph.addNode(codes[i], getShowCodesInGraph());
                        }

                        if (graph != null && top != null) {
                            graph.addEdge(top, temp);
                        }

                        graphAssociations(graph, temp, codes[i].getSourceOf(), true, true);
                        graphAssociations(graph, temp, codes[i].getTargetOf(), false, true);
                    }

                    primaryGraph.init(graph, "name");

                    if (twoGraphs) {
                        secondaryGraph.init(null, "name");
                    }
                    boolean hasNextTemp = false;
                    int numRemainingTemp = -1;

                    if (codeIterator_ != null && codes.length > 0) {
                        numRemainingTemp = codeIterator_.numberRemaining();
                        hasNextTemp = codeIterator_.hasNext();
                        if (!hasNextTemp) {
                            codeIterator_.release();
                            codeIterator_ = null;
                        }
                    }

                    if (hasNextTemp && !twoGraphs) {
                        TableItem ti = new TableItem(displayedCodeList_, SWT.NONE);
                        ti.setText("Fetch More Results (" + numRemainingTemp + " remaining)...");
                    }
                    stack_.topControl = resultsComposite_;
                    shell_.layout();
                    shell_.setCursor(null);
                } catch (final LBException e) {
                    e.printStackTrace();
                    log.error("Unexpected Error", e);
                    busyResolvingLabel_.setText(
                            "Sorry, an error occured while resolving the codes.  See the log for full details.  \n\n"
                                    + e.getMessage());
                    busyResolvingLabel_.getParent().layout();

                    progressBar_.setVisible(false);
                    shell_.setCursor(null);
                }
            }
        });
    }

    private void graphPropertyLinks(Graph graph, Node parentNode, ResolvedConceptReference rcr) {

        if (rcr == null || rcr.getEntity() == null)
            return;

        PropertyLink[] propertyLinks = rcr.getEntity().getPropertyLink();
        for (int i = 0; i < propertyLinks.length; i++) {
            PropertyLink propertyLink = propertyLinks[i];

            String sourcePropertyId = propertyLink.getSourceProperty();
            String targetPropertyId = propertyLink.getTargetProperty();

            String sourceText = "";
            String targetText = "";

            for (int j = 0; j < rcr.getEntity().getPresentation().length; j++) {
                Presentation pres = rcr.getEntity().getPresentation(j);
                String propertyId = pres.getPropertyId();
                if (propertyId.equals(sourcePropertyId)) {
                    sourceText = pres.getValue().getContent();
                }
                if (propertyId.equals(targetPropertyId)) {
                    targetText = pres.getValue().getContent();
                }

            }
            Node sourcePropertyLinkNode = graph
                    .addNode(
                            "[" + rcr.getConceptCode() + "]" + " - " + propertyLink.getSourceProperty() + " : "
                                    + sourceText,
                            rcr.getConceptCode() + propertyLink.getSourceProperty() + "source");
            Node targetPropertyLinkNode = graph
                    .addNode(
                            "[" + rcr.getConceptCode() + "]" + " - " + propertyLink.getTargetProperty() + " : "
                                    + targetText,
                            rcr.getConceptCode() + propertyLink.getTargetProperty() + "target");
            graph.addEdge(sourcePropertyLinkNode, targetPropertyLinkNode, propertyLink.getPropertyLink());
            graph.addEdge(parentNode, sourcePropertyLinkNode, "PropertyLink");
        }
    }

    private void graphAssociations(Graph graph, Node parentNode, AssociationList al, boolean down,
            boolean addToResults) {
        if (al != null && al.getAssociationCount() > 0) {
            Association[] aList = al.getAssociation();
            for (int i = 0; i < aList.length; i++) {
                Association a = aList[i];
                AssociatedConcept[] acList = a.getAssociatedConcepts().getAssociatedConcept();

                for (int j = 0; j < acList.length; j++) {
                    AssociatedConcept ac = acList[j];
                    if (addToResults)
                        addCodeToDisplayedResults(ac);
                    Node child = graph.addNode(ac, getShowCodesInGraph());

                    // Resolve the core association name ...
                    StringBuffer edgeText = new StringBuffer();
                    if (StringUtils.isNotBlank(a.getDirectionalName())) {
                        edgeText.append(a.getDirectionalName());
                    } else {
                        if (!down)
                            edgeText.append("[R]");
                        edgeText.append(a.getAssociationName());
                    }

                    // Add qualifiers, if available. Format 'assoc:qual(val),
                    // ...'
                    NameAndValueList aqList = ac.getAssociationQualifiers();
                    if (aqList != null && aqList.getNameAndValueCount() > 0) {
                        edgeText.append(':');
                        for (int k = 0; k < aqList.getNameAndValueCount(); k++) {
                            NameAndValue nv = aqList.getNameAndValue(k);
                            if (k > 0)
                                edgeText.append(", ");
                            edgeText.append(nv.getName());
                            if (StringUtils.isNotBlank(nv.getContent()))
                                edgeText.append('(').append(nv.getContent()).append(')');
                        }
                    }

                    // Limit the text length to protect use of horizontal space
                    graph.addEdge(parentNode, child, StringUtils.abbreviate(edgeText.toString(), 64));

                    if (down) {
                        graphAssociations(graph, child, ac.getSourceOf(), down, addToResults);
                    } else {
                        graphAssociations(graph, child, ac.getTargetOf(), down, addToResults);
                    }
                }
            }
        }
    }

    private class GraphResolver implements Runnable {
        private CodedNodeGraph cng_;
        private VDDisplayCodedNodeSet caller_;
        private SortOptionList sortOptions_;
        private boolean flat_;
        private boolean forward_, backward_;
        private int depth_, maxToReturn_;
        private ConceptReference focus_;

        public GraphResolver(CodedNodeGraph cng, VDDisplayCodedNodeSet caller, SortOptionList sortOptions,
                boolean flat, boolean forward, boolean backward, int depth, int maxToReturn,
                ConceptReference graphFocus) {
            cng_ = cng;
            caller_ = caller;
            sortOptions_ = sortOptions;
            flat_ = flat;
            forward_ = forward;
            backward_ = backward;
            depth_ = depth;
            focus_ = graphFocus;
            maxToReturn_ = maxToReturn;

        }

        public void run() {
            try {
                if (!flat_) {
                    graphRcr_ = cng_.resolveAsList(focus_, forward_, backward_, Integer.MAX_VALUE, depth_, null,
                            null, sortOptions_, maxToReturn_).getResolvedConceptReference();
                    try {
                        CodedNodeSet cns = cng_.toNodeList(focus_, forward_, backward_, depth_, maxToReturn_);
                        VDDisplayCodedNodeSet.this.codeIterator_ = cns.resolve(sortOptions_, null, null, null,
                                false);
                    } catch (Exception e) {
                        VDDisplayCodedNodeSet.this.codeIterator_ = null;
                    }
                } else {
                    CodedNodeSet cns = cng_.toNodeList(focus_, forward_, backward_, depth_, maxToReturn_);
                    VDDisplayCodedNodeSet.this.codeIterator_ = cns.resolve(sortOptions_, null, null, null, false);
                }
            } catch (LBException e) {
                caller_.resolveException_ = e;
            }

            caller_.resolveFinished(forward_);
        }
    }

    private class Resolver implements Runnable {
        private CodedNodeSet cns_;
        private VDDisplayCodedNodeSet caller_;
        private SortOptionList sortOptions_;

        public Resolver(CodedNodeSet cns, VDDisplayCodedNodeSet caller, SortOptionList sortOptions) {
            cns_ = cns;
            caller_ = caller;
            sortOptions_ = sortOptions;
        }

        public void run() {
            try {
                if (cns_ == null) {
                    caller_.resolveException_ = new LBException(
                            "There was a problem resolving Value Set Definition, please check the definition for any errors.");
                    caller_.resolveFinished(true);
                    return;
                }

                VDDisplayCodedNodeSet.this.codeIterator_ = cns_.resolve(sortOptions_, null, null, null, true);

            } catch (LBException e) {
                caller_.resolveException_ = e;
            }

            caller_.resolveFinished(true);
        }
    }

    private class UpdateSelectionGraphResolver implements Runnable {

        private ResolvedConceptReference rcr_;
        public boolean stop = false;
        private final VDGraphView graphView;
        private final ConceptTreeView treeView;

        public UpdateSelectionGraphResolver(ResolvedConceptReference rcr, final VDGraphView graphView,
                final ConceptTreeView treeView) {
            this.graphView = graphView;
            this.treeView = treeView;
            rcr_ = rcr;
        }

        public void run() {
            try {
                ResolvedConceptReference[] rcr;
                try {
                    stop = false;

                    LexBIGService lbs = LexBIGServiceImpl.defaultInstance();
                    CodingSchemeVersionOrTag csvt = new CodingSchemeVersionOrTag();
                    csvt.setVersion(rcr_.getCodingSchemeVersion());

                    CodingScheme cs = lbs.resolveCodingScheme(rcr_.getCodingSchemeName(), csvt);
                    Relations[] relationContainers = cs.getRelations();

                    ResolvedConceptReference[][] allRefs = new ResolvedConceptReference[relationContainers.length][];
                    int totalSize = 0;

                    // Resolve relationships from each container ...
                    for (int i = 0; i < relationContainers.length && !stop; i++) {
                        CodedNodeGraph cng = lb_gui_.getLbs()
                                .getNodeGraph(rcr_.getCodingSchemeName(),
                                        Constructors.createCodingSchemeVersionOrTagFromVersion(
                                                rcr_.getCodingSchemeVersion()),
                                        relationContainers[i].getContainerName());
                        ResolvedConceptReferenceList refs = cng.resolveAsList(rcr_, true, true, 0, 1, null, null,
                                null, -1);
                        allRefs[i] = refs.getResolvedConceptReference();
                        totalSize += refs.getResolvedConceptReferenceCount();
                    }

                    // Combine results into single array ...
                    rcr = new ResolvedConceptReference[totalSize];
                    int rcrPos = 0;
                    for (int i = 0; i < allRefs.length && !stop; i++) {
                        ResolvedConceptReference[] refs = allRefs[i];
                        for (int j = 0; j < refs.length; j++)
                            rcr[rcrPos++] = refs[j];
                    }
                } catch (LBParameterException e) {
                    e.printStackTrace();
                    Graph graph = new Graph(true);
                    graph.addNode(e.toString());
                    graphView.setGraph(graph);
                    // primaryGraph.setGraph(graph);
                    return;
                }

                if (!stop) {
                    Graph graph = new Graph(true);
                    treeView.clear();
                    shell_.getDisplay().asyncExec(new Runnable() {
                        public void run() {
                            treeView.getTree().setRedraw(false);
                        }
                    });

                    if (rcr.length == 0) {
                        graph.addNode(rcr_, getShowCodesInGraph());
                    } else {
                        for (int i = 0; i < rcr.length; i++) {
                            // there should only be one concept in this array.
                            // it is the top of the graph.
                            Node top = graph.addNode(rcr[i], getShowCodesInGraph());
                            String entity = null;
                            if (rcr[i].getEntityDescription() != null) {
                                entity = rcr[i].getEntityDescription().getContent();
                                if (entity != null) {
                                    entity = entity.trim();
                                }
                            }
                            Object sourceKey = new Object();
                            Object targetKey = new Object();
                            treeView.addTreeItem(treeView.getTree(), sourceKey, entity + " as association source");
                            treeView.addTreeItem(treeView.getTree(), targetKey, entity + " as association target");
                            TreeItem source = treeView.getKeyedTreeItem(sourceKey);
                            TreeItem target = treeView.getKeyedTreeItem(targetKey);

                            treeView.addAssociations(source, rcr[i].getSourceOf());
                            treeView.addAssociations(target, rcr[i].getTargetOf());
                            treeView.expand(source);
                            treeView.expand(target);

                            graphPropertyLinks(graph, top, rcr[i]);
                            graphAssociations(graph, top, rcr[i].getSourceOf(), true, false);
                            graphAssociations(graph, top, rcr[i].getTargetOf(), false, false);
                        }
                    }
                    graphView.setGraph(graph);
                    // primaryGraph.setGraph(graph);
                    shell_.getDisplay().asyncExec(new Runnable() {
                        public void run() {
                            treeView.getTree().setRedraw(true);
                        }
                    });
                }

            } catch (LBException e) {
                log.error("problem updating graph", e);
            }

        }
    }

    private class ResolveMore implements Runnable {

        public void run() {
            try {
                if (codeIterator_ != null && codeIterator_.hasNext()) {
                    final ResolvedConceptReference[] codes = codeIterator_.next(fetchSize)
                            .getResolvedConceptReference();
                    // gui update code
                    shell_.getDisplay().syncExec(new Runnable() {
                        public void run() {
                            // remove the - FETCHING_MORE item.
                            displayedCodeList_.remove(displayedCodeList_.getItemCount() - 1);
                        }
                    });

                    for (int i = 0; i < codes.length; i++) {
                        addCodeToDisplayedResults(codes[i]);
                    }
                    final int numRemaining = codeIterator_.numberRemaining();
                    final boolean hasNext = codeIterator_.hasNext();
                    if (!hasNext) {
                        codeIterator_.release();
                        codeIterator_ = null;
                    }

                    // gui update code
                    shell_.getDisplay().syncExec(new Runnable() {
                        public void run() {
                            if (hasNext) {
                                TableItem ti = new TableItem(displayedCodeList_, SWT.NONE);
                                ti.setText("Fetching More Results (" + numRemaining + " remaining)...");
                            }
                        }
                    });

                }
            } catch (LBException e) {
                dialog_.showError("Unexpected Error",
                        "There was an unexpected problem while getting more results - " + e.toString());
            }
        }

    }

    /*
     * If absent, adds the given reference to the maintained results and list
     * control.
     */
    private void addCodeToDisplayedResults(final ResolvedConceptReference rcr) {
        addOrUpdateDisplayedResults(rcr, -1, -1, -1, SWT.NONE, -1, -1, true);
    }

    /**
     * If absent, adds the given reference to the maintained results and list
     * control using the specified style settings. If present, alters the
     * existing list entry according to the given style settings.
     * 
     * @param rcr
     *            The resolved concept reference to display.
     * @param fontStyle
     *            The style to use for the associated list item; -1 for default
     *            (new item) or no change (existing item).
     * @param addFontStyle
     *            The font style if a list item is added; -1 for default.
     * @param addForeground
     *            The text color if a list item is added; -1 for default.
     * @param addBackground
     *            The area color if a list item is added; -1 for default.
     * @param updFontStyle
     *            The font style if a list item is updated; -1 for default.
     * @param updForeground
     *            The text color if a list item is updated; -1 for default.
     * @param updBackground
     *            The area color if a list item is updated; -1 for default.
     * @param replace
     *            True if an existing item should be removed (if present) and
     *            re-introduced at list end; false to maintain the current list
     *            item. If replaced, attributes from the old node are carried
     *            forward unless overridden by update parameters.
     */
    private void addOrUpdateDisplayedResults(final ResolvedConceptReference rcr, int addFontStyle,
            int addForeground, int addBackground, int updFontStyle, int updForeground, int updBackground,
            boolean replace) {
        int oldPos = -1;
        int newPos = -1;
        String qualifiedCode = new StringBuffer().append(rcr.getCodingSchemeName()).append(':')
                .append(rcr.getConceptCode()).append(':').append(rcr.getCodeNamespace()).toString();

        // Determine the position to alter, if item is new or the style has
        // changed.
        // Item is new?
        if (!(displayedResultsCodes_.contains(qualifiedCode))) {
            displayedResultsCodes_.add(qualifiedCode);
            displayedResults_.add(rcr);
            newPos = displayedResults_.size() - 1;
        }

        // Item is not new, do we need to alter the existing item?
        else if (replace || updFontStyle >= 0 || updForeground >= 0 || updBackground >= 0) {
            for (int i = 0; i < displayedResults_.size(); i++) {
                ResolvedConceptReference ref = displayedResults_.get(i);
                if (ref.getConceptCode().equals(rcr.getConceptCode())
                        && (ref.getCodingSchemeURI() == null
                                || ref.getCodingSchemeURI().equals(rcr.getCodingSchemeURI())
                                        && (ref.getCodeNamespace() == null
                                                || ref.getCodeNamespace().equals(rcr.getCodeNamespace())))
                        && (ref.getCodingSchemeVersion() == null
                                || ref.getCodingSchemeVersion().equals(rcr.getCodingSchemeVersion()))) {
                    oldPos = i;
                    break;
                }
            }
            if (oldPos >= 0) {
                if (replace) {
                    displayedResults_.remove(oldPos).getConceptCode();
                    displayedResults_.add(rcr);
                    newPos = displayedResults_.size() - 1;
                } else
                    newPos = oldPos;
            }
        }

        // Was the position set to indicate a new or changed item?
        if (newPos >= 0) {
            boolean isAdd = oldPos < 0;
            final int fNewPos = newPos;
            final int fOldPos = oldPos;
            final int fStyle = isAdd ? addFontStyle : updFontStyle;
            final int fFrgnd = isAdd ? addForeground : updForeground;
            final int fBkgnd = isAdd ? addBackground : updBackground;

            shell_.getDisplay().syncExec(new Runnable() {
                public void run() {
                    int fontStyle = fStyle;
                    Color foreColor = null;
                    Color backColor = null;
                    FontData data[] = null;

                    // Preserve old item properties on replace ...
                    if (fOldPos >= 0 && fNewPos != fOldPos) {
                        TableItem tiOld = displayedCodeList_.getItem(fOldPos);
                        if (fontStyle < 0)
                            data = tiOld.getFont().getFontData();
                        if (fFrgnd < 0)
                            foreColor = tiOld.getForeground();
                        if (fBkgnd < 0)
                            backColor = tiOld.getBackground();
                        displayedCodeList_.remove(fOldPos);
                    }

                    // Fetch or create a new item to satisfy the request ...
                    TableItem ti = (fNewPos == fOldPos) ? displayedCodeList_.getItem(fOldPos)
                            : new TableItem(displayedCodeList_, SWT.NONE, fNewPos);

                    // Merge new item properties ...
                    if (fontStyle >= 0) {
                        data = ti.getFont().getFontData();
                        for (int i = 0; i < data.length; i++)
                            data[i].setStyle(data[i].getStyle() | fontStyle);
                        Font newFont = new Font(shell_.getDisplay(), data);
                        ti.setFont(newFont);
                    }
                    if (fFrgnd >= 0)
                        foreColor = shell_.getDisplay().getSystemColor(fFrgnd);
                    if (foreColor != null)
                        ti.setForeground(foreColor);
                    if (fBkgnd >= 0)
                        backColor = shell_.getDisplay().getSystemColor(fBkgnd);
                    if (backColor != null)
                        ti.setBackground(backColor);

                    // Finally, set the text ...
                    ti.setText(new StringBuffer().append(rcr.getConceptCode()).append(" - ")
                            .append(rcr.getEntityDescription() != null
                                    ? (rcr.getEntityDescription().getContent() != null
                                            ? rcr.getEntityDescription().getContent()
                                            : "")
                                    : "")
                            .toString());
                }
            });
        }
    }

    /*
     * When a graph node is selected, I want to find it in the code list, and
     * select it there.
     */
    int loop;

    protected void graphItemSelected(final ResolvedConceptReference rcr) {
        // deselect current item ...
        shell_.getDisplay().syncExec(new Runnable() {
            public void run() {
                displayedCodeList_.deselectAll();
            }
        });

        // ensure the new item is in the list ...
        addOrUpdateDisplayedResults(rcr, SWT.ITALIC, SWT.COLOR_BLUE, -1, SWT.NONE, SWT.COLOR_BLUE, -1, false);

        // attempt to find and select the matching item ...
        for (loop = 0; loop < displayedResults_.size(); loop++) {
            ResolvedConceptReference cur = displayedResults_.get(loop);

            if (cur.getCodingSchemeURI().equals(rcr.getCodingSchemeURI())
                    && cur.getConceptCode().equals(rcr.getConceptCode())) {
                shell_.getDisplay().syncExec(new Runnable() {
                    public void run() {
                        displayedCodeList_.select(loop);
                        displayedCodeList_.showSelection();
                    }
                });
                break;
            }
        }

        // update the details view
        displayConceptDetails(rcr);
        updateGraphForConceptSelection(rcr);
    }

    /**
     * Indicates whether codes should be displayed with text in the graph.
     */
    public boolean getShowCodesInGraph() {
        return showCodes_selected;
    }

    /**
     * Indicates whether edges should be drawn between secondary nodes.
     */
    public boolean getShowSecondaryRelInGraph() {
        return showSecondaryRel_selected;
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        if (codeIterator_ != null) {
            codeIterator_.release();
            codeIterator_ = null;
        }
    }
}