edu.ku.brc.specify.tasks.ExpressSearchTask.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.specify.tasks.ExpressSearchTask.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.specify.tasks;

import static edu.ku.brc.ui.UIRegistry.getResourceString;
import static org.apache.commons.lang.StringUtils.isNotEmpty;

import java.awt.Color;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import edu.ku.brc.af.auth.PermissionSettings;
import edu.ku.brc.af.core.AppContextMgr;
import edu.ku.brc.af.core.ContextMgr;
import edu.ku.brc.af.core.MenuItemDesc;
import edu.ku.brc.af.core.NavBoxIFace;
import edu.ku.brc.af.core.SubPaneIFace;
import edu.ku.brc.af.core.SubPaneMgr;
import edu.ku.brc.af.core.ToolBarItemDesc;
import edu.ku.brc.af.core.UsageTracker;
import edu.ku.brc.af.core.db.DBFieldInfo;
import edu.ku.brc.af.core.db.DBTableIdMgr;
import edu.ku.brc.af.core.db.DBTableInfo;
import edu.ku.brc.af.core.expresssearch.ERTIJoinColInfo;
import edu.ku.brc.af.core.expresssearch.ExpressResultsTableInfo;
import edu.ku.brc.af.core.expresssearch.ExpressSearchConfigCache;
import edu.ku.brc.af.core.expresssearch.ExpressSearchConfigDlg;
import edu.ku.brc.af.core.expresssearch.QueryAdjusterForDomain;
import edu.ku.brc.af.core.expresssearch.QueryForIdResultsHQL;
import edu.ku.brc.af.core.expresssearch.QueryForIdResultsSQL;
import edu.ku.brc.af.core.expresssearch.SearchConfig;
import edu.ku.brc.af.core.expresssearch.SearchConfigService;
import edu.ku.brc.af.core.expresssearch.SearchTableConfig;
import edu.ku.brc.af.prefs.AppPreferences;
import edu.ku.brc.af.tasks.subpane.SimpleDescPane;
import edu.ku.brc.af.ui.ESTermParser;
import edu.ku.brc.af.ui.SearchBox;
import edu.ku.brc.af.ui.SearchTermField;
import edu.ku.brc.af.ui.db.ERTICaptionInfo;
import edu.ku.brc.af.ui.db.JAutoCompTextField;
import edu.ku.brc.af.ui.db.PickListDBAdapterFactory;
import edu.ku.brc.af.ui.db.QueryForIdResultsIFace;
import edu.ku.brc.dbsupport.CustomQueryIFace;
import edu.ku.brc.dbsupport.CustomQueryListener;
import edu.ku.brc.dbsupport.JPAQuery;
import edu.ku.brc.dbsupport.RecordSetIFace;
import edu.ku.brc.dbsupport.SQLExecutionListener;
import edu.ku.brc.dbsupport.SQLExecutionProcessor;
import edu.ku.brc.specify.SpecifyUserTypes.UserType;
import edu.ku.brc.specify.datamodel.CollectingEvent;
import edu.ku.brc.specify.datamodel.Collection;
import edu.ku.brc.specify.datamodel.Discipline;
import edu.ku.brc.specify.datamodel.SpecifyUser;
import edu.ku.brc.specify.dbsupport.SpecifyQueryAdjusterForDomain;
import edu.ku.brc.specify.tasks.subpane.ESResultsSubPane;
import edu.ku.brc.specify.tasks.subpane.ESResultsTablePanelIFace;
import edu.ku.brc.specify.tasks.subpane.ExpressSearchResultsPaneIFace;
import edu.ku.brc.specify.tasks.subpane.ExpressTableResultsFromQuery;
import edu.ku.brc.specify.tasks.subpane.SIQueryForIdResults;
import edu.ku.brc.specify.tasks.subpane.qb.QBQueryForIdResultsHQL;
import edu.ku.brc.specify.tasks.subpane.qb.QBResultsSubPane;
import edu.ku.brc.specify.ui.HelpMgr;
import edu.ku.brc.specify.web.ExplorerESPanel;
import edu.ku.brc.ui.CommandAction;
import edu.ku.brc.ui.CommandDispatcher;
import edu.ku.brc.ui.CommandListener;
import edu.ku.brc.ui.CustomDialog;
import edu.ku.brc.ui.IconEntry;
import edu.ku.brc.ui.IconManager;
import edu.ku.brc.ui.JStatusBar;
import edu.ku.brc.ui.RolloverCommand;
import edu.ku.brc.ui.SearchBoxComponent;
import edu.ku.brc.ui.UIHelper;
import edu.ku.brc.ui.UIRegistry;

/**
 * This task will enable the user to index the database and preform express searches. This is where the Express Search starts.
 *
 * @code_status Complete
 *
 * @author rods
 *
 */
public class ExpressSearchTask extends BaseTask
        implements CommandListener, SQLExecutionListener, CustomQueryListener {
    // Static Data Members
    private static final Logger log = Logger.getLogger(ExpressSearchTask.class);
    public static final String GLOBAL_SEARCH_AVAIL = "GLOBAL_SEARCH_AVAIL";
    public static final String GLOBAL_SEARCH = "GLOBAL_SEARCH";

    public static final int RESULTS_THRESHOLD = 20000;
    public static final String EXPRESSSEARCH = "Express_Search";
    public static final String CHECK_INDEXER_PATH = "CheckIndexerPath";

    protected Color selectionFG = UIManager.getColor("TextField.selectionForeground");
    protected Color selectionBG = UIManager.getColor("TextField.selectionBackground");

    // Static Data Members
    protected static ExpressSearchTask instance = null;
    protected static final String LAST_SEARCH = "lastsearch";

    // Data Members
    protected JCheckBoxMenuItem globalSearchCheckBoxMI;
    protected SearchBoxComponent searchBoxComp;
    protected SearchBox searchBox;
    protected JTextField searchText;
    protected JButton searchBtn;
    protected Color textBGColor = null;
    protected Color badSearchColor = new Color(255, 235, 235);

    protected Vector<ESResultsSubPane> paneCache = new Vector<ESResultsSubPane>();

    protected Vector<SQLExecutionProcessor> sqlProcessorList = new Vector<SQLExecutionProcessor>();
    protected boolean sqlHasResults = false;
    protected Vector<CustomQueryIFace> queryList = new Vector<CustomQueryIFace>();
    protected int queryCount = 0;
    protected int queryCountDone = 0;

    protected ESResultsSubPane queryResultsPane = null;
    protected SIQueryForIdResults searchWarningsResults = null;
    protected JStatusBar statusBar = null;
    protected boolean doingDebug = false;

    /**
     * Default Constructor.
     */
    public ExpressSearchTask() {
        super(EXPRESSSEARCH, getResourceString(EXPRESSSEARCH));

        iconName = "Search";

        closeOnLastPane = true;

        CommandDispatcher.register(EXPRESSSEARCH, this);

        instance = this;
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.core.Taskable#initialize()
     */
    @Override
    public void initialize() {
        if (!isInitialized) {
            super.initialize(); // sets isInitialized to false

            statusBar = UIRegistry.getStatusBar();
        }
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.tasks.BaseTask#setEnabled(boolean)
     */
    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        if (searchBox != null) {
            searchBox.setEnabled(enabled);
        }
    }

    /**
     * Returns true if the talk has been started and false if it hasn't.
     * @return true if the talk has been started and false if it hasn't.
     */
    public static boolean isStarted() {
        return instance != null;
    }

    /**
     * Check to see of the index has been run and then enables the express search controls.
     *
     */
    /**
     * 
     */
    public void appContextHasChanged() {
        if (searchText != null) {
            if (searchText instanceof JAutoCompTextField) {
                ((JAutoCompTextField) searchText)
                        .setPickListAdapter(PickListDBAdapterFactory.getInstance().create("ExpressSearch", true));
            }

            AppPreferences localPrefs = AppPreferences.getLocalPrefs();
            searchText.setText(localPrefs.get(getLastSearchKey(), ""));
        }

        if (searchBtn != null) {
            searchBtn.setEnabled(true);
            searchText.setEnabled(true);
        }

        if (textBGColor != null) {
            searchText.setBackground(textBGColor);
            searchText.setForeground(UIManager.getColor("TextField.foreground"));
        }

        SearchConfigService.getInstance().reset();

        if (searchBox != null && searchBox.getMenuCreator() != null) {
            searchBox.getMenuCreator().reset();
        }
    }

    /**
     * @return a discipline based pref name.
     */
    protected String getLastSearchKey() {
        Discipline discp = AppContextMgr.getInstance().getClassObject(Discipline.class);
        String disciplineName = discp != null ? ("_" + discp.getType()) : "";
        return LAST_SEARCH + disciplineName;
    }

    /**
     * Performs the express search and returns the results.
     */
    protected void doQuery() {
        sqlHasResults = false;

        if (true) {
            searchText.setBackground(textBGColor);
            searchText.setForeground(UIManager.getColor("TextField.foreground"));

            String searchTerm = searchText.getText();
            if (isNotEmpty(searchTerm)) {
                if (searchTerm.length() == 2 && (searchTerm.endsWith("*") || searchTerm.startsWith("*"))) {
                    UIRegistry.showLocalizedError("ExpressSearchTask.NO_SINGLE_CHAR");

                } else if (QueryAdjusterForDomain.getInstance()
                        .isUserInputNotInjectable(searchTerm.toLowerCase())) {
                    boolean isOK = true;
                    if (searchTerm.startsWith("*") && searchTerm.endsWith("*") && searchTerm.length() > 3) {
                        int inx = searchTerm.length() - 2;
                        if (searchTerm.indexOf(' ', 2) > 1 && searchTerm.lastIndexOf(' ') < searchTerm.length() - 2
                                && searchTerm.charAt(1) != '"' && searchTerm.charAt(1) != '\''
                                && searchTerm.charAt(1) != '`' && searchTerm.charAt(inx) != '"'
                                && searchTerm.charAt(inx) != '\'' && searchTerm.charAt(inx) != '`') {
                            JLabel label = UIHelper.createI18NLabel("ExpressSearchTask.MISSING_QUOTES");
                            PanelBuilder pb = new PanelBuilder(new FormLayout("f:p:g", "f:p:g"));
                            pb.add(label, (new CellConstraints()).xy(1, 1));
                            pb.setDefaultDialogBorder();
                            CustomDialog dlg = new CustomDialog((Frame) UIRegistry.getMostRecentWindow(),
                                    getResourceString("HINT"), true, pb.getPanel());
                            dlg.setOkLabel(getResourceString("ExpressSearchTask.SRCH_ANYWAY"));
                            dlg.setCancelLabel(getResourceString("ExpressSearchTask.DNT_SRCH"));
                            dlg.setVisible(true);
                            isOK = !dlg.isCancelled();
                        }
                    }

                    if (isOK) {
                        ESResultsSubPane expressSearchPane = new ESResultsSubPane(searchTerm, this, true);
                        if (!doQuery(searchText, null, expressSearchPane)) {
                            setUserInputToNotFound("BAD_SEARCH_TERMS", true);

                        } else {
                            AppPreferences.getLocalPrefs().put(getLastSearchKey(), searchTerm);
                        }
                    }

                } else {
                    setUserInputToNotFound("ES_SUSPICIOUS_SQL", true);
                }
            }
        } else {
            String searchTerm = searchText.getText();

            ExplorerESPanel explorerSearch = new ExplorerESPanel();

            doQuery(searchTerm, explorerSearch);

            explorerSearch.done();
        }
    }

    /**
     * @param searchTerm
     * @param esrp
     */
    public boolean doQuery(final String searchTerm, final ExpressSearchResultsPaneIFace esrp) {
        if (isNotEmpty(searchTerm)) {
            if (QueryAdjusterForDomain.getInstance().isUserInputNotInjectable(searchTerm.toLowerCase())) {
                return doQuery(null, searchTerm, esrp);
            }
        }
        return false;
    }

    /**
     * @param esrPane the main display pane
     * @param searchTableConfig the configuration information
     * @param searchTerm the search term for the search
     * @return the JPAQuery
     */
    protected synchronized JPAQuery startSearchJPA(final ExpressSearchResultsPaneIFace esrPane,
            final SearchTableConfig searchTableConfig, final String searchTerm, final List<SearchTermField> terms) {
        JPAQuery jpaQuery = null;

        String sqlStr = searchTableConfig.getSQL(terms, true, true);
        if (sqlStr != null) {
            jpaQuery = new JPAQuery(sqlStr, this);
            jpaQuery.setData(new Object[] { searchTableConfig, esrPane, searchTerm });
            queryList.add(jpaQuery);
            queryCount++;

            if (statusBar != null) {
                statusBar.setProgressRange(EXPRESSSEARCH, 0, queryCount, queryCountDone);
            }

            if (esrPane.doQueriesSynchronously()) {
                jpaQuery.execute();

            } else {
                jpaQuery.start();
            }
        }
        return jpaQuery;
    }

    /**
     * Performs the express search and returns the results to the ExpressSearchResultsPaneIFace.
     * If the control is null then it will use the string.
     *
     * @param searchTextArg the Text Control that contains the search string (can be null)
     * @param searchTextStr the Text Control that contains the search string (can be null)
     * @param tables ExpressResultsTableInfo hash
     * @param esrPane the pane that the results will be set into
     * @return true if results were found, false if not results
     */
    public synchronized boolean doQuery(final JTextField searchTextArg, final String searchTextStr,
            final ExpressSearchResultsPaneIFace esrPane) {

        doingDebug = AppPreferences.getLocalPrefs().getBoolean("esdebug", false);
        searchWarningsResults = null;

        String searchTerm = (searchTextArg != null ? searchTerm = searchTextArg.getText() : searchTextStr);

        if (!ESTermParser.getInstance().parse(searchTerm, false)) {
            setUserInputToNotFound("BAD_SEARCH_TERMS", false);
            return false;
        }

        //boolean hasResults = true;
        if (StringUtils.isNotEmpty(searchTerm)) {
            SearchTableConfig context = SearchConfigService.getInstance().getSearchContext();
            if (context == null) {
                SearchConfig config = SearchConfigService.getInstance().getSearchConfig();

                if (config.getTables().size() > 0) {
                    sqlHasResults = false;
                    if (searchTextArg != null) {
                        searchTextArg.setEnabled(false);
                    }
                    if (searchBtn != null) {
                        searchBtn.setEnabled(false);
                    }

                    queryList.clear(); // Just in case
                    queryCount = 0;
                    queryCountDone = 0;

                    int cnt = 0;
                    for (SearchTableConfig table : config.getTables()) {
                        if (!table.getTableInfo().isHidden()) {
                            if (AppContextMgr.isSecurityOn()) {
                                if (table.getTableInfo().getPermissions().canView()) {
                                    if (startSearchJPA(esrPane, table, searchTerm,
                                            ESTermParser.getInstance().getFields()) != null) {
                                        cnt++;
                                    }
                                } else {
                                    log.debug("Skipping [" + table.getTableInfo().getTitle() + "]");
                                }
                            } else {
                                if (startSearchJPA(esrPane, table, searchTerm,
                                        ESTermParser.getInstance().getFields()) != null) {
                                    cnt++;
                                }
                            }
                        }
                    }

                    if (cnt == 0) {
                        setUserInputToNotFound("NO_FIELDS_TO_SEARCH", true);
                        searchText.setEnabled(true);
                        searchBtn.setEnabled(true);
                        return false;
                    }

                    // Check to see if any queries got started.
                    if (queryList.size() == 0) {
                        completionUIHelper(null);
                    } else {
                        return true;
                    }

                } else {
                    searchTextArg.getToolkit().beep();
                }

            } else {
                if (startSearchJPA(esrPane, context, searchTerm, ESTermParser.getInstance().getFields()) != null) {
                    return true;
                }
                setUserInputToNotFound("NO_FIELDS_TO_SEARCH", true);
                return true; // if we return false then this error gets overwritten with a different error
            }
        } else {
            //System.err.println("SearchTableConfig service has not been loaded or is empty.");
            log.error("SearchTableConfig service has been loaded or is empty.");
        }
        return false;
    }

    /**
     * Traverses the individual result record ids and maps them into the result tables.
     * @param config
     * @param tableId
     * @param searchTerm
     * @param resultSet
     * @param id
     * @param joinIdToTableInfoHash
     * @param resultsForJoinsHash the related results table
     */
    protected void collectResults(final SearchConfig config, final String tableId, final String searchTerm,
            final ResultSet resultSet, final Integer id,
            final Hashtable<String, List<ExpressResultsTableInfo>> joinIdToTableInfoHash,
            final Hashtable<String, QueryForIdResultsSQL> resultsForJoinsHash) {
        try {
            Integer recId;
            if (resultSet != null) {
                recId = resultSet.getInt(1);
            } else {
                recId = id;
            }

            //System.out.println("id "+id+"  "+recId);

            //log.debug("Find any Joins for TableID ["+tblInfo.getTableId()+"]");

            // Start by getting the List of next round of 'view' queries 
            // Before getting here we have constructed list of the queries that will need to be run
            // when we get a hit from the current table against one of the joins in the view query
            // 
            List<ExpressResultsTableInfo> list = joinIdToTableInfoHash.get(tableId);
            if (list != null) {
                // Now loop through each of the view queries
                for (ExpressResultsTableInfo erti : list) {
                    //log.debug("Not Active: "+erti.getId()+"  "+erti.getTitle()+"  "+config.isActiveForRelatedQueryId(erti.getId()));
                    if (!config.isActiveForRelatedQueryId(erti.getId())) {
                        continue;
                    }

                    //log.debug("Id: "+erti.getId()+"  "+erti.getTitle()+"  "+erti.getTableInfo().getPermissions().canView());
                    //SecurityMgr.dumpPermissions(erti.getTableInfo().getTitle(), erti.getTableInfo().getPermissions().getOptions());
                    if (AppContextMgr.isSecurityOn()) {
                        if (!erti.getTableInfo().getPermissions().canView()) {
                            continue;
                        }

                        boolean hasUnviewableCol = false;
                        for (ERTICaptionInfo capInfo : erti.getCaptionInfo()) {
                            DBFieldInfo fldInfo = capInfo.getFieldInfo();
                            if (fldInfo != null) {
                                if (!fldInfo.getTableInfo().getPermissions().canView()) {
                                    hasUnviewableCol = true;
                                    break;
                                }

                            } else if (capInfo.getAggClass() != null) {
                                DBTableInfo aggTblInfo = DBTableIdMgr.getInstance()
                                        .getByShortClassName(capInfo.getAggClass().getSimpleName());
                                if (aggTblInfo != null && !aggTblInfo.getPermissions().canAdd()) {
                                    hasUnviewableCol = true;
                                    break;
                                }
                            } else {
                                log.error("*********** NO FIELD: " + capInfo.getColName());
                            }
                        }
                        if (hasUnviewableCol) {
                            continue;
                        }
                    }

                    QueryForIdResultsSQL results = resultsForJoinsHash.get(erti.getId());
                    if (results == null) {
                        Integer joinColTableId = null;
                        ERTIJoinColInfo joinCols[] = erti.getJoins();
                        if (joinCols != null) {
                            for (ERTIJoinColInfo jci : joinCols) {
                                if (tableId.equals(jci.getJoinTableId())) {
                                    joinColTableId = jci.getJoinTableIdAsInt();
                                    //log.debug("CHK: "+jci.getTableInfo().getTitle()+"  "+jci.getTableInfo().getPermissions().canView());
                                    if (AppContextMgr.isSecurityOn()
                                            && !jci.getTableInfo().getPermissions().canView()) {
                                        continue;
                                    }
                                    break;
                                }
                            }
                        }
                        if (joinColTableId == null) {
                            throw new RuntimeException("Shouldn't have got here!");
                        }
                        Integer displayOrder = SearchConfigService.getInstance().getSearchConfig()
                                .getOrderForRelatedQueryId(erti.getId());
                        //log.debug("ExpressSearchResults erti.getId()["+erti.getId()+"] joinColTableId["+joinColTableId+"] displayOrder["+displayOrder+"]");
                        results = new QueryForIdResultsSQL(erti.getId(), joinColTableId, erti, displayOrder,
                                searchTerm);
                        resultsForJoinsHash.put(erti.getId(), results);
                    }

                    if (doingDebug) {
                        log.debug("*** Adding recId[" + recId + "] to erti[" + erti.getId() + "] ");
                    }
                    results.add(recId);
                }
            }
        } catch (SQLException ex) {
            edu.ku.brc.af.core.UsageTracker.incrSQLUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ExpressSearchTask.class, ex);
            ex.printStackTrace();
        }
    }

    /**
     * Traverses through the results and adds to the panel to be displayed.
     * @param resultsMap the primary result tables
     * @param resultsForJoinsMap the related results table
     */
    protected void displayResults(final ExpressSearchResultsPaneIFace esrPane,
            final QueryForIdResultsIFace queryResults,
            final Hashtable<String, QueryForIdResultsSQL> resultsForJoinsMap) {
        // For Debug Only
        if (false && resultsForJoinsMap != null) {
            for (Enumeration<QueryForIdResultsSQL> e = resultsForJoinsMap.elements(); e.hasMoreElements();) {
                QueryForIdResultsSQL qfirsql = e.nextElement();
                if (qfirsql.getRecIds().size() > 0) {
                    log.debug("\n\n------------------------------------");
                    log.debug("------------------------------------");
                    log.debug("Search Id " + qfirsql.getTableInfo().getId() + " Table Id "
                            + qfirsql.getTableInfo().getTableId() + " Column Name " + qfirsql.getJoinColTableId());
                    log.debug("------------------------------------");
                    for (Integer l : qfirsql.getRecIds()) {
                        log.debug(l + " ");
                    }
                }
            }
        }

        if (queryResults.size() > 0) {
            esrPane.addSearchResults(queryResults);
        }

        if (resultsForJoinsMap != null) {
            for (QueryForIdResultsSQL rs : resultsForJoinsMap.values()) {
                if (rs.getRecIds().size() > 0) {
                    esrPane.addSearchResults(rs);
                }
            }
            resultsForJoinsMap.clear();
        }
    }

    /**
     * @param recordSet
     */
    public void displayRecordSet(final RecordSetIFace recordSet, final boolean isEditable) {
        if (recordSet.getNumItems() > 0) {
            SearchConfig config = SearchConfigService.getInstance().getSearchConfig();
            SearchTableConfig searchTableConfig = config.getSearchTableConfigById(recordSet.getDbTableId());
            if (searchTableConfig != null) {
                String rsName = UIRegistry.getLocalizedMessage("ES_RS_TAB_NM", recordSet.getName());

                SubPaneIFace sp = SubPaneMgr.getInstance().getSubPaneByName(rsName);
                if (sp != null) {
                    SubPaneMgr.getInstance().showPane(sp);
                } else {
                    ESResultsSubPane esrPane = new ESResultsSubPane(rsName, this, true);
                    esrPane.setIcon(IconManager.getIcon("Record_Set", IconManager.IconSize.Std16));
                    Hashtable<String, QueryForIdResultsSQL> resultsForJoinsHash = new Hashtable<String, QueryForIdResultsSQL>();
                    QueryForIdResultsHQL results = new QueryForIdResultsHQL(searchTableConfig,
                            new Color(255, 158, 6), recordSet);
                    results.setEditable(isEditable);
                    results.setExpanded(true);
                    displayResults(esrPane, results, resultsForJoinsHash);
                    addSubPaneToMgr(esrPane);
                }
            } else {
                String tblTitle = DBTableIdMgr.getInstance().getTitleForId(recordSet.getDbTableId());
                UIRegistry.showLocalizedError("RS_CONFIG_SEARCH", tblTitle);
            }
        } else {
            UIRegistry.showLocalizedError("RS_HAS_NO_ITEMS", recordSet.getName());
        }
    }

    /**
     * @param searchName
     */
    public void doBasicSearch(final String searchName) {
        Hashtable<String, ExpressResultsTableInfo> idToTableInfoMap = ExpressSearchConfigCache
                .getSearchIdToTableInfoHash();
        for (ExpressResultsTableInfo erti : idToTableInfoMap.values()) {
            //log.debug("["+erti.getName()+"]["+searchName+"]");
            if (erti.getName().equals(searchName)) {
                // This needs to be fixed in that it might not return any results
                // and we are always adding the pane.
                ESResultsSubPane expressSearchPane = new ESResultsSubPane(erti.getTitle(), this, true);
                QueryForIdResultsSQL esr = new QueryForIdResultsSQL(erti.getTitle(), null, erti, 0, "");
                @SuppressWarnings("unused")
                ExpressTableResultsFromQuery esrfq = new ExpressTableResultsFromQuery(expressSearchPane, esr, true);
                addSubPaneToMgr(expressSearchPane);
                return;
            }
        }
        log.error("Can't find a search definition for name [" + searchName + "]");
    }

    /**
     * Executes and displays an HQL Query.
     * 
     * @param hqlStr the HQL query string
     */
    protected void doHQLQuery(final QueryForIdResultsIFace results, final Boolean reusePanel) {
        if (reusePanel == null || !reusePanel) {
            ESResultsSubPane expressSearchPane = new ESResultsSubPane(getResourceString("ES_QUERY_RESULTS"), this,
                    true);
            addSubPaneToMgr(expressSearchPane);
            expressSearchPane.addSearchResults(results);

        } else {
            if (queryResultsPane == null) {
                //queryResultsPane = new ESResultsSubPane(getResourceString("ES_QUERY_RESULTS"), this, true);
                queryResultsPane = new QBResultsSubPane(getResourceString("ES_QUERY_RESULTS"), this, true);
                queryResultsPane.setIcon(IconManager.getIcon("Query", IconManager.IconSize.Std16));

            } else {
                queryResultsPane.reset();
            }
            queryResultsPane.addSearchResults(results);
        }
    }

    //-------------------------------------------------------
    // Taskable
    //-------------------------------------------------------

    /* (non-Javadoc)
     * @see edu.ku.brc.af.core.BaseTask#getStarterPane()
     */
    @Override
    public SubPaneIFace getStarterPane() {
        return starterPane = new SimpleDescPane(name, this, "This is the Express Search Pane");
    }

    /*
     *  (non-Javadoc)
     * @see edu.ku.brc.af.core.Taskable#getNavBoxes()
     */
    @Override
    public java.util.List<NavBoxIFace> getNavBoxes() {
        initialize();

        Vector<NavBoxIFace> extendedNavBoxes = new Vector<NavBoxIFace>();

        extendedNavBoxes.clear();
        extendedNavBoxes.addAll(navBoxes);

        RecordSetTask rsTask = (RecordSetTask) ContextMgr.getTaskByClass(RecordSetTask.class);

        List<NavBoxIFace> nbs = rsTask.getNavBoxes();
        if (nbs != null) {
            extendedNavBoxes.addAll(nbs);
        }

        return extendedNavBoxes;
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.core.Taskable#getToolBarItems()
     */
    @Override
    public List<ToolBarItemDesc> getToolBarItems() {
        toolbarItems = new Vector<ToolBarItemDesc>();

        ActionListener doQuery = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                doQuery();
            }
        };

        searchBoxComp = new SearchBoxComponent(new SearchBoxMenuCreator(), doQuery, false,
                PickListDBAdapterFactory.getInstance().create("ExpressSearch", true));
        searchBoxComp.createUI();
        searchBox = searchBoxComp.getSearchBox();
        searchText = searchBoxComp.getSearchText();
        searchBtn = searchBoxComp.getSearchBtn();
        textBGColor = searchBoxComp.getTextBGColor();
        badSearchColor = searchBoxComp.getBadSearchColor();

        searchBtn.setToolTipText(getResourceString("ExpressSearchTT"));
        HelpMgr.setHelpID(searchBtn, "Express_Search");
        HelpMgr.registerComponent(searchText, "Express_Search");

        AppPreferences localPrefs = AppPreferences.getLocalPrefs();
        searchText.setText(localPrefs.get(getLastSearchKey(), ""));
        textBGColor = searchText.getBackground();

        searchText.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                showContextMenu(e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                showContextMenu(e);

            }
        });

        toolbarItems.add(new ToolBarItemDesc(searchBoxComp, ToolBarItemDesc.Position.AdjustRightLastComp));

        return toolbarItems;
    }

    /**
     * Shows the Reset menu.
     * @param e the mouse event
     */
    protected void showContextMenu(MouseEvent e) {
        if (e.isPopupTrigger()) {
            JPopupMenu popup = new JPopupMenu();
            JMenuItem menuItem = new JMenuItem(UIRegistry.getResourceString("ES_TEXT_RESET"));
            menuItem.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent ex) {
                    searchText.setEnabled(true);
                    searchText.setBackground(textBGColor);
                    searchText.setText("");

                    if (statusBar != null) {
                        statusBar.setProgressDone(EXPRESSSEARCH);
                    }
                }
            });
            popup.add(menuItem);
            popup.show(e.getComponent(), e.getX(), e.getY());

        }
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.tasks.BaseTask#getMenuItems()
     */
    @Override
    public List<MenuItemDesc> getMenuItems() {
        return new Vector<MenuItemDesc>();
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.tasks.BaseTask#getTaskClass()
     */
    @Override
    public Class<? extends BaseTask> getTaskClass() {
        return this.getClass();
    }

    //----------------------------------------------------------------
    //-- CommandListener Interface
    //----------------------------------------------------------------

    /* (non-Javadoc)
     * @see edu.ku.brc.af.tasks.BaseTask#doProcessAppCommands(edu.ku.brc.ui.CommandAction)
     */
    @Override
    protected void doProcessAppCommands(CommandAction cmdAction) {
        super.doProcessAppCommands(cmdAction);

        if (cmdAction.isAction(APP_RESTART_ACT)) {
            appContextHasChanged();
        }
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.tasks.BaseTask#doCommand(edu.ku.brc.ui.CommandAction)
     */
    @Override
    public void doCommand(CommandAction cmdAction) {
        super.doCommand(cmdAction);

        if (cmdAction.isType(EXPRESSSEARCH)) {
            UsageTracker.incrUsageCount("ES." + cmdAction.getType());

            if (cmdAction.isAction("HQL")) {
                doHQLQuery((QueryForIdResultsIFace) cmdAction.getData(),
                        (Boolean) cmdAction.getProperty("reuse_panel"));

            } else if (cmdAction.isAction("ExpressSearch")) {
                String searchTerm = cmdAction.getData().toString();
                ESResultsSubPane expressSearchPane = new ESResultsSubPane(searchTerm, this, true);
                doQuery(null, searchTerm, expressSearchPane);

            } else if (cmdAction.isAction("Search")) {
                doBasicSearch(cmdAction.getData().toString());

            } else if (cmdAction.isAction("SearchComplete")) {
                doSearchComplete(cmdAction);

            } else if (cmdAction.isAction("ViewRecordSet")) {
                RecordSetIFace recordSet = null;
                if (cmdAction.getData() instanceof RecordSetIFace) {
                    recordSet = (RecordSetIFace) cmdAction.getData();

                } else if (cmdAction.getData() instanceof RolloverCommand) {
                    RolloverCommand roc = (RolloverCommand) cmdAction.getData();
                    if (roc.getData() instanceof RecordSetIFace) {
                        recordSet = (RecordSetIFace) roc.getData();
                    }
                }
                if (recordSet != null) {
                    displayRecordSet(recordSet, (Boolean) cmdAction.getProperty("canModify"));
                }
            }
        }
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.tasks.BaseTask#subPaneRemoved(edu.ku.brc.af.core.SubPaneIFace)
     */
    @Override
    public void subPaneRemoved(SubPaneIFace subPane) {
        if (subPane == queryResultsPane) {
            queryResultsPane = null;
        }
        super.subPaneRemoved(subPane);
    }

    //-------------------------------------------------------------
    // SQLExecutionListener Interface
    //-------------------------------------------------------------
    /* (non-Javadoc)
     * @see edu.ku.brc.dbsupport.SQLExecutionListener#exectionDone(edu.ku.brc.dbsupport.SQLExecutionProcessor, java.sql.ResultSet)
     */
    //@Override
    public synchronized void exectionDone(final SQLExecutionProcessor process, final ResultSet resultSet) {
        if (!sqlHasResults) {
            try {
                sqlHasResults = resultSet.first();

            } catch (SQLException ex) {
                ex.printStackTrace();
                edu.ku.brc.af.core.UsageTracker.incrSQLUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ExpressSearchTask.class, ex);
            }
        }
        sqlProcessorList.remove(process);

        Object[] data = (Object[]) process.getData();
        if (data != null) {
            if (data.length == 3) {
                SearchTableConfig searchTableConfig = (SearchTableConfig) data[0];
                ExpressSearchResultsPaneIFace esrPane = (ExpressSearchResultsPaneIFace) data[1];
                String searchTerm = (String) data[2];

                Hashtable<String, ExpressResultsTableInfo> idToTableInfoHash = ExpressSearchConfigCache
                        .getSearchIdToTableInfoHash();
                Hashtable<String, List<ExpressResultsTableInfo>> joinIdToTableInfohash = ExpressSearchConfigCache
                        .getJoinIdToTableInfoHash();
                Hashtable<String, QueryForIdResultsSQL> resultsForJoinsHash = new Hashtable<String, QueryForIdResultsSQL>();

                try {
                    if (resultSet.next()) {
                        String searchIdStr = Integer.toString(searchTableConfig.getTableInfo().getTableId());
                        ExpressResultsTableInfo tblInfo = idToTableInfoHash.get(searchIdStr);
                        if (tblInfo == null) {
                            throw new RuntimeException("Bad id from search[" + searchIdStr + "]");
                        }

                        SearchConfig config = SearchConfigService.getInstance().getSearchConfig();

                        int cnt = 0;
                        do {
                            if (cnt < RESULTS_THRESHOLD) {
                                collectResults(config, tblInfo.getTableId(), searchTerm, resultSet, null,
                                        joinIdToTableInfohash, resultsForJoinsHash);
                            }
                            cnt++;
                        } while (resultSet.next());

                        //System.err.println("SQLExecutionProcessor: "+cnt);

                        if (cnt >= RESULTS_THRESHOLD) {
                            String reason = String.format(
                                    getResourceString("ExpressSearchTask.MAX_SEARCH_RESULTS_EXCEEDED"),
                                    RESULTS_THRESHOLD, cnt);
                            if (searchWarningsResults == null) {
                                searchWarningsResults = new SIQueryForIdResults();
                                searchWarningsResults.addReason(searchTableConfig, reason);
                                displayResults(esrPane, searchWarningsResults, resultsForJoinsHash);

                            } else {
                                searchWarningsResults.addReason(searchTableConfig, reason);
                            }
                        }

                        if (resultsForJoinsHash.size() > 0) {
                            QueryForIdResultsSQL queryResults = new QueryForIdResultsSQL(searchIdStr, null, tblInfo,
                                    searchTableConfig.getDisplayOrder(), searchTerm);
                            displayResults(esrPane, queryResults, resultsForJoinsHash);
                        }
                    }
                } catch (SQLException ex) {
                    edu.ku.brc.af.core.UsageTracker.incrSQLUsageCount();
                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ExpressSearchTask.class, ex);
                    ex.printStackTrace();
                }

            }
        }
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.dbsupport.SQLExecutionListener#executionError(edu.ku.brc.dbsupport.SQLExecutionProcessor, java.lang.Exception)
     */
    //@Override
    public synchronized void executionError(SQLExecutionProcessor process, Exception ex) {
        sqlProcessorList.remove(process);

    }

    /**
     * Changes the UI component to show that nothing was found.
     */
    protected void setUserInputToNotFound(final String msgKey, final boolean isInError) {
        if (isInError) {
            if (badSearchColor != null) {
                searchText.setBackground(badSearchColor);
            }
            searchText.setSelectionStart(0);
            searchText.setSelectionEnd(searchText.getText().length());

        } else {
            //searchText.setBackground(selectionBG);

        }
        searchText.getToolkit().beep();
        searchText.repaint();
        searchText.requestFocus();

        if (isInError) {
            if (statusBar != null) {
                statusBar.setLocalizedErrorMessage(msgKey);
            }
            UIRegistry.writeTimedSimpleGlassPaneMsg(getResourceString(msgKey), Color.RED);

        } else {
            displayNoResults(msgKey);
        }
    }

    /**
     * Displays "No Results Message
     * @param msgKey the localized string key
     */
    protected void displayNoResults(final String msgKey) {
        String fullMsg = UIRegistry.getLocalizedMessage(
                StringUtils.isNotEmpty(msgKey) ? msgKey : "NoExpressSearchResults", searchText.getText());
        UIRegistry.writeTimedSimpleGlassPaneMsg(fullMsg, null, null, 24, true);
    }

    //-------------------------------------------------------------------------
    //-- CustomQueryListener Interface
    //-------------------------------------------------------------------------

    protected synchronized void completionUIHelper(final CustomQueryIFace customQuery) {

        if (customQuery != null) {
            queryList.remove(customQuery);
            queryCountDone++;
        }

        if (statusBar != null) {
            statusBar.setValue(EXPRESSSEARCH, queryCountDone);
        }

        //System.err.println(customQuery.hashCode()+"  "+queryList.size());
        if (queryList.size() == 0) {
            if (searchText != null) {
                searchText.setEnabled(true);
                searchBtn.setEnabled(true);

                if (!sqlHasResults) {
                    setUserInputToNotFound("NoExpressSearchResults", false);

                } else {
                    searchText.setSelectionStart(searchText.getText().length());
                    searchText.setSelectionEnd(searchText.getText().length());
                    searchText.repaint();

                    if (statusBar != null) {
                        statusBar.setText("");
                    }
                }
            }
            CommandDispatcher.dispatch(new CommandAction(EXPRESSSEARCH, "SearchComplete"));
        }
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.dbsupport.CustomQueryListener#exectionDone(edu.ku.brc.dbsupport.CustomQuery)
     */
    //@Override
    public synchronized void exectionDone(final CustomQueryIFace customQuery) {
        boolean addPane = false;
        JPAQuery jpaQuery = (JPAQuery) customQuery;
        List<?> list = jpaQuery.getDataObjects();

        if (!sqlHasResults) {
            sqlHasResults = !jpaQuery.isInError() && list != null && list.size() > 0;
            addPane = sqlHasResults;
            //System.err.println("AddPane: "+addPane+"  Err "+jpaQuery.isInError()+"  "+(list != null && list.size() > 0));
        }

        if (list != null) {
            if (list.size() > 0) {
                Object[] data = (Object[]) jpaQuery.getData();
                SearchTableConfig searchTableConfig = (SearchTableConfig) data[0];
                final ExpressSearchResultsPaneIFace esrPane = (ExpressSearchResultsPaneIFace) data[1];
                String searchTerm = (String) data[2];

                if (addPane && esrPane instanceof SubPaneIFace) {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            addSubPaneToMgr((SubPaneIFace) esrPane);
                        }
                    });
                }

                Hashtable<String, List<ExpressResultsTableInfo>> joinIdToTableInfoHash = ExpressSearchConfigCache
                        .getJoinIdToTableInfoHash();
                Hashtable<String, QueryForIdResultsSQL> resultsForJoinsHash = new Hashtable<String, QueryForIdResultsSQL>();

                //log.debug("TID["+searchTableConfig.getTableInfo().getTableId() + "] Table Order ["+searchTableConfig.getDisplayOrder()+"] "+list.size());
                SearchConfig config = SearchConfigService.getInstance().getSearchConfig();

                String tableIdStr = Integer.toString(searchTableConfig.getTableInfo().getTableId());

                int cnt = 0;
                for (Object idObj : list) {
                    if (cnt < RESULTS_THRESHOLD) {
                        collectResults(config, tableIdStr, searchTerm, null, (Integer) idObj, joinIdToTableInfoHash,
                                resultsForJoinsHash);
                    }
                    cnt++;
                }

                //System.err.println("CustomQueryIFace: "+cnt);

                if (cnt >= RESULTS_THRESHOLD) {
                    //String reason = String.format("%d hits returned of %d maximum allowed. ", RESULTS_THRESHOLD, cnt); // I18N
                    //String reason = String.format(getResourceString("QB_HITS_MAX_ALLOWED"), RESULTS_THRESHOLD, cnt); // I18N
                    String reason = UIRegistry.getFormattedResStr("QB_HITS_MAX_ALLOWED", RESULTS_THRESHOLD, cnt);
                    if (searchWarningsResults == null) {
                        searchWarningsResults = new SIQueryForIdResults();
                        searchWarningsResults.addReason(searchTableConfig, reason);
                        displayResults(esrPane, searchWarningsResults, resultsForJoinsHash);

                    } else {
                        searchWarningsResults.addReason(searchTableConfig, reason);
                    }
                }

                QueryForIdResultsIFace results = new QueryForIdResultsHQL(searchTableConfig,
                        new Color(30, 144, 255), searchTerm, list);
                results.setMultipleSelection(true);
                displayResults(esrPane, results, resultsForJoinsHash);

                //joinIdToTableInfoHash.clear();
            }

        } else {
            log.error("List was null and cant't be");
        }

        completionUIHelper(customQuery);
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.dbsupport.CustomQueryListener#executionError(edu.ku.brc.dbsupport.CustomQuery)
     */
    //@Override
    public synchronized void executionError(final CustomQueryIFace customQuery) {
        log.error("Error running query!");
        completionUIHelper(customQuery);
    }

    /**
     * @return the permissions array
     */
    @Override
    protected boolean[][] getPermsArray() {
        return new boolean[][] { { true, true, true, true }, { true, true, true, true },
                { true, true, false, false }, { true, false, false, false } };
    }

    //-------------------------------------------------------------------------
    //-- CustomQueryListener Interface
    //-------------------------------------------------------------------------
    public class SearchBoxMenuCreator implements SearchBox.MenuCreator {
        protected List<JComponent> menus = null;
        protected SearchConfigService scService;
        protected JMenuItem allMenuItem = null;
        protected JMenuItem configMenuItem = null;
        protected ActionListener action;

        /**
         * Constructor.
         */
        public SearchBoxMenuCreator() {
            scService = SearchConfigService.getInstance();

            action = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if (e.getSource() == allMenuItem) {
                        scService.setSearchContext(null);

                    } else if (e.getSource() == configMenuItem) {
                        ExpressSearchConfigDlg dlg = new ExpressSearchConfigDlg();
                        dlg.createUI();
                        UIHelper.centerAndShow(dlg); // modal
                        dlg.cleanUp();

                    } else {
                        String miTitle = ((JMenuItem) e.getSource()).getText();
                        for (SearchTableConfig stc : scService.getSearchConfig().getTables()) {
                            if (stc.getTitle().equals(miTitle)) {
                                scService.setSearchContext(stc);
                            }
                        }
                    }
                }
            };
        }

        /* (non-Javadoc)
         * @see edu.ku.brc.ui.SearchBox.MenuCreator#createPopupMenus()
         */
        public List<JComponent> createPopupMenus() {
            if (menus == null) {
                menus = new Vector<JComponent>();
                allMenuItem = new JMenuItem(getResourceString("ALL"), SearchBox.getSearchIcon());
                allMenuItem.addActionListener(action);
                menus.add(allMenuItem);

                for (SearchTableConfig stc : scService.getSearchConfig().getTables()) {
                    // This needed for the first time in before there are any settings
                    if (AppContextMgr.isSecurityOn()) {
                        PermissionSettings perm = stc.getTableInfo().getPermissions();
                        if (!perm.canView()) {
                            continue;
                        }
                    }

                    JMenuItem menuItem = new JMenuItem(stc.getTitle(),
                            IconManager.getIcon(stc.getIconName(), IconManager.IconSize.Std16));
                    menuItem.addActionListener(action);
                    menus.add(menuItem);

                    if (stc.getTableInfo().getTableId() == CollectingEvent.getClassTableId()) {
                        boolean isEmbedded = AppContextMgr.getInstance().getClassObject(Collection.class)
                                .getIsEmbeddedCollectingEvent();
                        IconEntry ciEntry = IconManager
                                .getIconEntryByName(isEmbedded ? "collectinginformation" : "ce_restore");
                        menuItem.setIcon(ciEntry.getIcon(IconManager.IconSize.Std16));
                    }
                }

                if (!AppContextMgr.isSecurityOn() || SpecifyUser.isCurrentUserType(UserType.Manager)) {
                    boolean permsOKForGlobalSearch = ((SpecifyQueryAdjusterForDomain) QueryAdjusterForDomain
                            .getInstance()).isPermsOKForGlobalSearch();
                    boolean isGlobalSearchAvail = permsOKForGlobalSearch
                            && AppPreferences.getLocalPrefs().getBoolean("GLOBAL_SEARCH_AVAIL", false);
                    if (isGlobalSearchAvail) {
                        boolean isGSOn = AppPreferences.getLocalPrefs().getBoolean("GLOBAL_SEARCH", false);

                        ActionListener globalSearchAL = new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                doGlobalSearchSetup();
                            }
                        };

                        globalSearchCheckBoxMI = new JCheckBoxMenuItem(getResourceString(GLOBAL_SEARCH),
                                IconManager.getIcon("GlobalSearch", IconManager.IconSize.Std16), isGSOn);
                        globalSearchCheckBoxMI.addActionListener(globalSearchAL);

                        menus.add(new JSeparator());
                        menus.add(globalSearchCheckBoxMI);
                    }
                } else {
                    AppPreferences.getLocalPrefs().remove(GLOBAL_SEARCH);
                }

                if (globalSearchCheckBoxMI == null) {
                    menus.add(new JSeparator());
                }
                configMenuItem = new JMenuItem(getResourceString("ESConfig"),
                        IconManager.getIcon("SystemSetup", IconManager.IconSize.Std16));
                configMenuItem.addActionListener(action);
                menus.add(configMenuItem);
            }

            return menus;
        }

        /* (non-Javadoc)
         * @see edu.ku.brc.ui.SearchBox.MenuCreator#reset()
         */
        public void reset() {
            this.menus = null;
        }
    }

    /**
     * 
     */
    private void doGlobalSearchSetup() {
        if (globalSearchCheckBoxMI.isSelected()) {
            AppPreferences.getLocalPrefs().putBoolean(GLOBAL_SEARCH, true);
        } else {
            AppPreferences.getLocalPrefs().remove(GLOBAL_SEARCH);
            searchBox.resetSearchIcon();
        }
    }

    /**
     * @param results
     * @return
     */
    protected boolean isQueryBuilderResults(final QueryForIdResultsIFace results) {
        //return queryResultsPane != null && results != null && queryResultsPane.contains(results);
        /* strange, seemingly windows-only issue (see doSearchComplete()) also arises when
         * the results have not yet been added to the queryResultsPane when doSearchComplete() is executed
         * (same reason esrto.hasResults() in doSearchComplete() returns false),
         * so must check type of results.
         */
        return queryResultsPane != null && results instanceof QBQueryForIdResultsHQL;
    }

    /**
     * @param cmdAction
     */
    protected void doSearchComplete(final CommandAction cmdAction) {
        if (statusBar != null) {
            statusBar.setProgressDone(EXPRESSSEARCH);
            if (cmdAction.getData() instanceof JPAQuery) {
                QueryForIdResultsIFace results = (QueryForIdResultsIFace) cmdAction
                        .getProperty("QueryForIdResultsIFace");
                ESResultsTablePanelIFace esrto = (ESResultsTablePanelIFace) cmdAction
                        .getProperty("ESResultsTablePanelIFace");

                if (!isQueryBuilderResults(results) && esrto != null && !esrto.hasResults()) {
                    /* hmmmmmm.... A strange, seemingly windows-only issue has been occurring where
                     * the propertyChange event that updates the table used in the esrto.hasResults() call
                     * has not finished when the if statement above is executed, so esrto.hasResults() incorrectly
                     * returns false. I have added the !isQueryBuilderResults() condition because so far this problem has only
                     * occurred for the QueryBuilder and I don't know if the method for determining 'hasResults()'
                     * in the QueryBuilder results block below are applicable for all types of results.
                     * 
                     * We occasionally see this on a Virtual machine, more investigation is needed.
                     * 
                     */
                    //displayNoResults("QB_NO_RESULTS");
                    results.complete();
                    UIRegistry.showLocalizedError("QB_NO_RESULTS_UNK");
                    return;
                }

                //Only execute this block for QueryBuilder results...
                if (isQueryBuilderResults(results)) {
                    int rowCount = ((JPAQuery) cmdAction.getData()).getDataObjects().size();
                    boolean isError = ((JPAQuery) cmdAction.getData()).isInError();
                    boolean isCancelled = ((JPAQuery) cmdAction.getData()).isCancelled();
                    boolean showPane = !isError && !isCancelled && rowCount > 0;
                    //print status bar msg if error or rowCount == 0, 
                    //else show the queryResults pane if rowCount > 0
                    int index = SubPaneMgr.getInstance().indexOfComponent(queryResultsPane.getUIComponent());
                    if (index == -1) {
                        if (showPane) {
                            addSubPaneToMgr(queryResultsPane);
                        }
                    } else {
                        if (showPane) {
                            SubPaneMgr.getInstance().showPane(queryResultsPane);
                        } else {
                            SubPaneMgr.getInstance().removePane(queryResultsPane, false);
                        }
                    }
                    results.complete();
                    if (isError) {
                        statusBar.setErrorMessage(getResourceString("QB_RUN_ERROR"));
                    }

                    else if (rowCount == 0) {
                        displayNoResults("QB_NO_RESULTS");
                    } else {
                        statusBar.setText(null);
                    }
                }
            }
        }
    }
}