net.refractions.udig.catalog.ui.wizard.DataBaseRegistryWizardPage.java Source code

Java tutorial

Introduction

Here is the source code for net.refractions.udig.catalog.ui.wizard.DataBaseRegistryWizardPage.java

Source

/*
 *    uDig - User Friendly Desktop Internet GIS client
 *    http://udig.refractions.net
 *    (C) 2004-2007, Refractions Research Inc.
 *    (C) 2007,      Adrian Custer.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
 * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
 *
 */
package net.refractions.udig.catalog.ui.wizard;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.sql.DataSource;

import net.refractions.udig.catalog.ui.CatalogUIPlugin;
import net.refractions.udig.catalog.ui.internal.Messages;
import net.refractions.udig.ui.PlatformGIS;

import org.apache.commons.dbcp.BasicDataSource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;

// TODO: HTMLify this javadoc
/**
 * David's magic superclass reduced to linear, documented, boring reality so that it may be
 * understandable by mortals; this is an abstract superclass for implementations of the
 * 'IWizardPage' interface required by the 'wizardPage' portion of the
 * <code>net.refractions.udig.catalog.ui.connectionFactory</code> extension point contract with the
 * uDig catalog system. The connectionFactory extension point needs a DataStore factory to make the
 * connection used by the Catalog and a IWizardPage to obtain from the user the parameters which
 * will be used by the factory. The IWizardPage interface extends the eclipse RCP 'Import...' system
 * by providing a User Interface SWT Group which will be placed in a 'Page' of the import wizard and
 * will obtain the required parameters to connect to some resource, in this case a database (Db)
 * server. Concrete extensions of this class will then use the parameters to connect to the server
 * using approaches specific to each Database Management System (DBMS). WARNING: Modifications to
 * this class must consider the consequences for all extending classes, notably both
 * PostGisWizardPage and AbstractProprietaryDatastoreWizardPage. ************* David's magic spells
 * (now for mortals) *********************** This class performs a number of actions as explained
 * below. These actions have been changed from happening magically in response to users clicking on
 * the widgets to happening after user input or button clicks. Hopefully this logic will be more
 * predicatable, robust, and understandable. Establish default Connection Parameters: * must be
 * added by the extending class during its construction * are used to set the current connection
 * parameters at the same time * TODO: let the user reset to this in the case where the user is lost
 * Get Storage for Connection Parameters: * must be obtained or created by the extending class'
 * constructor. Get and Use Stored Connection Parameters: * are taken from storage and added to the
 * list by the extending class during its construction. * are added to the drop down list during *
 * TODO: limit the parameters added to a few recent Retain Successful Connection Parameters: * are
 * added to the list after each successful connection Store Successful Connection Parameters: * are
 * stored to the storage system after each successful connection Show the Advanced group: * by the
 * widgetSelected(.) handler for the check button widget if this widget is clicked (checked).
 * Activate the lookup and connect buttons: * by the modifyText(.) handler for any of the input
 * widgets, if the current host, port, user, password, and database parameters are all filled out.
 * Lookup the available databases and schema on the server: * by the widgetSelected(.) handler for
 * the "Lookup" button, when it is clicked. Connect to a database server: * by the widgetSelected(.)
 * handler for the "Connect" button, when it is clicked. Activate the finish buttons: * by the
 * widgetSelected(.) handler for the "Connect" button if, after the connection attempt, there is a
 * live connection and the parameter map built from the current connection can be processed by the
 * DataStore factory. Reset the lists of available resources when altering key connection params: *
 * by the modifyText(.) handlers for each of the widgets: host, port, user, and password, when they
 * are modified. Still to be done: (some of these are distant hopes) pre-select text on re-edit: *
 * Note this seems to be the default when using the <tab> key to move through the widgets Hint text
 * completion from the storage list: * Note this requires improvement in the earlier logic.
 * Importantly, we must be able to connect to a resource that is a subset of an earlier resource,
 * i.e. if a previous connection was made to the host "serverAlex," a user must still be able to
 * connect to the host "serverA" by typing 's' 'e' 'r' 'v' 'e' 'r' 'A' '<return>' without our
 * completion logic getting in the way of the user. Validate input: * This is to be done in three
 * parts, character exclusion, URL component validation, and URL validation: - changes with
 * characters in the 'invalidChar*List' lists will not be allowed (and add an error in the RCP
 * Animated Area). - changes with character sequences in the 'invalidString*List' lists will not be
 * allowed (and add an error in the RCP Animated Area). - URLs will be subject to a coarse
 * verification before being used to connect to a database. Password entry warnings: * If CapsLock
 * is set during password entry, an error will be placed in the RCP Animated Area. Connection Status
 * Information: * Will be displayed in the dialog. Verifications of permissions: * the permissions
 * of the user on the server's database will be obtained and reported to the user. Verification of
 * the database: * since we can only use spatial tables, the databases offered to the user should be
 * evaluated to ensure they can hold spatial data. ****************** Class Outline (i.e. the key
 * pieces) ********************
 * 
 * <pre>
 * 
 *   FIELDS:                      // The fields describe here all use instances 
 *                                // of the inner class 
 *                                //   DataBaseConnInfo
 *                                // which is essentially a structure of
 *                                //       : host 
 *                                //       : port 
 *                                //       : user 
 *                                //       : ?pass? 
 *                                //         NOTE: the password field should 
 *                                //               probably be dropped in the
 *                                //               future since we want to treat 
 *                                //               it specially for safety.
 *                                //       : database 
 *                                //       : schema 
 *                                //       : timestamp (for sorting) 
 *   
 *       * currentDBCI            - The connection parameters gathered by the 
 *                                  GUI and used to make the final connection.
 *                                  
 *       * defaultDBCI            - Parameters which generally apply to the DBMS
 *                                - The database name will be used during initial
 *                                  lookup of the available databases and schema.
 *                                - The values will be provided as hints to the 
 *                                  user.
 *                            !MUST BE PROVIDED BY THE EXTENDING CONSTRUCTOR!
 *                            
 *       * storedDBCIList         - A java.util.List of DBCI which may be empty 
 *                                  if no successful connections have been made 
 *                                  or will hold a list of all the connections 
 *                                  made along with their timestamps.
 *   
 *   
 *   CONSTRUCTORS:                // Merely call the superclass with a String 
 *                                // for the page title area
 *   
 *   
 *   UTILITY METHODS:             // These are internal to the uDig system of 
 *                                // Database connection dialogs and therefore 
 *                                // only required by our needs.
 *   
 *   
 *   CONTRACT METHODS:            // Satisfy extension point contracts and 
 *                                // interface requirements.
 *   
 *       * setVisible             //TODO: document
 *       
 *       * isPageComplete         //TODO: document
 *       
 *       * createControl          // This creates the GUI as follows:
 *                                //   1. Instantiate the widgets
 *                                //   2. Populate the 'Previous' drop down list
 *                                //   3. Hook up the listeners
 *                                //   4? Connect the tab traversal
 *                                //   5? set page complete
 *       
 *       * createAdvancedControl  // Implemented in extending classes to add 
 *                                // GUI elements for DBMS specific parameters
 *       
 *       * getConnection          // THE WHOLE POINT, here is abstract, will be
 *                                // implemented with DBMS specific logic by the 
 *                                // concrete extendors of this class
 *   
 *   LOOKUP METHODS               // Two methods to lookup the databases and 
 *                                // schemata available
 *                                
 *       * lookupDB               - Gets a String array of available database
 *                                  names
 *       
 *       * lookupSchema           - Gets a String array of available schema
 *                                - names
 *   
 *   EVENT HANDLERS:
 *   
 *       * focusGain              //Does little
 *       
 *       * focusLoss              //Does little
 *       
 *       * verifyText             //Not yet implemented
 *           
 *       * modifyText             //Handles *all* the modification logic:
 *                                - uses the widget text to set the appropriate 
 *                                  current connection parameter
 *                                - resets the available database and schema 
 *                                  lists if they are no longer valid
 *                                - activates the lookup and connect buttons if
 *                                  the parameters are complete enough
 *       
 *       * widgetSelected         //Handles the button clicked events
 *       
 *           -lookupButtonWdg     - connects to the server with the default 
 *                                  database/schema and gets the list of 
 *                                  available databases and schemata.
 *                                  
 *           -connectButtonWdg    - makes the connection using currentDBCI.
 *           
 *           -advButtonWdg        - exposes the advanced section of the GUI.
 *           
 *       * widgetDefaultSelected  //Not used
 *   
 *   
 *   DataBaseConnInfo class       // A bean inner class, essentially a structure
 *                                // to hold the connection parameters and a 
 *                                // timestamp for the last successful 
 *                                // connection using those parameters.
 * 
 * 
 * </pre>
 * 
 * ****************** Contract with Concrete Extending Classses *************** This class, being
 * abstract, is designed specifically for the needs of the extending classes, notably the
 * PostGISWizardPage and the AbstractProprietaryDatastoreWizardPage classes. See
 * 
 * @see net.refractions.udig.catalog.internal.postgis.ui.PostGisWizardPage for the cannonical
 *      example of how to use (extend) this class in a concrete implementation. This class
 *      implicitly establishes the following contract with its extendors: I. EXTENDING CLASSES MUST:
 *      Implement a constructor which 1. calls this constructor, idealy with an appropriate string
 *      for the title area. 2. gets an IDialogSettings instance from the RCP storage system,
 *      creating a new instance if none is available. 3. populates the past connection list 4.
 *      populates the db and schema exclusion lists 5. TODO: populates the invalid character and
 *      characterSequence lists. Implement the abstract methods, most importantly the
 *      getConnection(.) method that will be used to make a test connection with the host. Override
 *      the createControl(..) method with an initial call to super.createControl(..args..) and then
 *      add logic to handle drag-and-drop (TODO). II. Extending classes may: Implement
 *      createAdvancedControl(..) to return an SWT Group widget which contains all the input widgets
 *      to obtain any DBMS specific advanced parameters desired, and handle all the appropriate
 *      event logic that ensues. Override the getDatabaseResultSet(..) and/or the
 *      getSchemasResultSet(..), if a different technique is necessary to retrieve a list of
 *      Databases or Schemas. ????????????????? DROP THIS SECTION AS REPETITIVE
 *      ????????????????????????? Note also: Extending classes wishing to expand the event handling
 *      logic should be aware of the following design for the UI event handling system: The JDBC
 *      'Connection' to the Db or Schema on the DBMS will be obtained in response to the user
 *      clicking on the "Connect" button - This will be performed by the selectionListener(..)
 *      method tied to the connectButton. The selectionListener will eventually call the
 *      getConnection(..) method assuming the paramters to use are stored in the currConn
 *      DataBaseConnInfo field. The list of databases and schema available to the user on the DBMS
 *      will be obtained in response to the user clicking on the "Lookup" button - The
 *      selectionListener tied to to the button will create a temporary, dummy connection to the
 *      DBMS, possibly using some default database generally available on the specific DBMS if the
 *      user has not yet named any more specific database. The list of available databases and
 *      schema will be reset if the user changes any of the key connection parameters - If the user
 *      modifies the host, port, user, or password parameters, the list of available databases and
 *      schema will be reset to null. Parameters for successful connections will be stored into the
 *      eclipse RCP settings system and retrieved on page construction - Values will be obtained
 *      from the eclipse storage system and placed into a java.util.List field. The UI will offer
 *      the user a drop down list of past successful values and selection by the user will cause
 *      both the values to be stored into the currInfo object and into the text area of the input
 *      widgets. TODO: Input will be verified both character by character during input to the GUI
 *      widgets and as overall urls prior to connection - ? should this happen as each widget is
 *      about to loose focus? ? There are two strategies to help child classes: either a bunch of
 *      new methods can be created with names like verifyHostText() or we can create inner Listener
 *      classes. TODO: When focus arrives on an entry widget, the contents should be pre-selected so
 *      that direct input will obliterate existing values - TODO: The system must ignore focus
 *      events due to the user moving the mouse around the desktop. Auto-completion of values based
 *      on previous successful connection. TODO: Make sure the user actively must accept the
 *      auto-completed text so that a prior connection to 'localhost' does not prevent a future
 *      connection to 'local', i.e. the user should be able to type 'l', 'o', 'c', 'a', 'l',
 *      '<return>' and not have the completion hint in the way.
 *      ****************************************************************************
 * @author David Zwiers, dzwiers, for Refractions Research, Inc.
 * @author Jody Garnett, jody, for Refractions Research, Inc.
 * @author Jesse Eichar, jeichar, for Refractions Research, Inc.
 * @author Richard Gould, rgould, for Refractions Research, Inc.
 * @author Amr Alam, aalam, for Refractions Research, Inc.
 * @author Justin Deoliveira, jdeolive, for Refractions Research, Inc.
 * @author Cory Horner, chorner, for Refractions Research, Inc.
 * @author Adrian Custer, acuster.
 * @author Harry Bullen, hbullen.
 * @since 0.3
 */
public abstract class DataBaseRegistryWizardPage extends DataStoreWizardPage
        implements FocusListener, ModifyListener, SelectionListener
// TODO: ,VerifyListener
{

    // PARAMETERS for connection
    /**
     * The parameters we will use to make any eventual connection. Parameters are presumed to be
     * valid once stored in this object. These Parameters will be obtained via the GUI from the
     * user.
     */
    protected final DataBaseConnInfo currentDBCI = new DataBaseConnInfo(""); //$NON-NLS-1$
    /**
     * The parameters which work as defaults for the particular DBMS of the concrete extender; will
     * be populated during construction.
     */
    protected final DataBaseConnInfo defaultDBCI = new DataBaseConnInfo(""); //$NON-NLS-1$
    /**
     * The parameters of any previous successful connection, obtained from storage during
     * construction of the concrete extending class, added to following any successful connection
     * and stored prior to exit. Copy new DBCI's into this list with DataBaseConnInfo dbci = new
     * DataBaseConnInfo(""); storedDBCIList.add(dbci.setParameters(dbciToAdd)) rather than adding
     * the DBCI directly in order to preserve the separation of instances.
     */
    protected final java.util.List<DataBaseConnInfo> storedDBCIList = new ArrayList<DataBaseConnInfo>();
    /**
     * The RCP structure to hold and store the successful connection parameters. This must be here
     * because we need to store the settings on successful connection.
     */
    protected IDialogSettings settings; // guaranteed non-null after
    // construction

    /**
     * The connection used to actually connect with the database. Don't use this directly instead
     * call getDataSource() and use what it returns.
     */
    protected BasicDataSource dataSource = null;

    /**
     * The name of the section used to store the successful connection parameter settings in the RCP
     * storage system.
     */
    protected String settingsArrayName;
    // WIDGETS
    protected Combo rcntComboWgt = null;
    protected Text hostTextWgt = null;
    protected Text portTextWgt = null;
    protected Text userTextWgt = null;
    protected Text passTextWgt = null;
    protected Combo dbComboWgt = null;
    protected Combo schemaComboWgt = null;
    protected Button lookupBtnWgt = null;
    protected Button connectBtnWgt = null;
    protected Button advancedBtnWgt = null;
    protected Group advancedGrp = null;
    // STATE variables for the Logic
    private Widget wgtLostFocus = null; // To ignore focusGain on widgets that
    // just lost focus
    // EXCLUSION Lists
    /**
     * The names of any databases which should not be offered to the user, generally used for
     * databases that are part of the DBMS itself. The list will be populated during construction.
     */
    protected final java.util.List<String> dbExclusionList = new ArrayList<String>();
    /**
     * The names of any schemata which should not be offered to the user, generally used for
     * schemata that are part of the DBMS itself. The list will be populated during construction.
     */
    protected final java.util.List<String> schemaExclusionList = new ArrayList<String>();

    // VALIDATION Lists
    // protected final java.util.List<Character> invalidCharList = new ArrayList
    // <Character> ();
    // protected final java.util.List<Character> invalidHostCharList = new
    // ArrayList <Character> ();
    // protected final java.util.List<Character> invalidUserCharList = new
    // ArrayList <Character> ();
    // protected final java.util.List<Character> invalidPassCharList = new
    // ArrayList <Character> ();
    // protected final java.util.List<String> invalidHostSeqList = new ArrayList
    // <String> ();
    // protected final java.util.List<String> invalidUserSeqList = new ArrayList
    // <String> ();
    // protected final java.util.List<String> invalidPassSeqList = new ArrayList
    // <String> ();

    // CONSTRUCTORS
    /**
     * The usual (?only one used?) constructor.
     * 
     * @param header The string presented to the user in the topmost part of the wizard page.
     */
    public DataBaseRegistryWizardPage(String header) {
        super(header);
    }

    // UTILITY METHODS
    /**
     * Checks if the DBMS uses Schema or not; if true, the schema widget will be shown and the
     * schema parameter passed to the DBMS during connect.
     * 
     * @return true if the DBMS uses a Schema.
     */
    protected abstract boolean dbmsUsesSchema();

    /**
     * Checks the database name against those that should not be offered to the user for connection;
     * by default, all database names are acceptable so the method always returns false. The
     * constructor of implementing classes should add appropriate names to the exclusion list.
     * 
     * @param d the name of the database to check.
     * @return true if the name should be excluded from those presented to the user. Here it will be
     *         false always, because by default the dbExclusionList is empty.
     */
    protected boolean excludeDbFromUserChoices(String d) {
        if (dbExclusionList.contains(d))
            return true;
        return false;
    }

    /**
     * Checks the schema name against those that should not be offered to the user for connection;
     * by default, all schema names are acceptable so the method always returns false. The
     * constructor of implementing classes should add appropriate names to the exclusion list.
     * 
     * @param s the name of the schema to check.
     * @return true if the name should be excluded from those presented to the user. Here it will be
     *         false always, because by default the schemaExclusionList is empty.
     */
    protected boolean excludeSchemaFromUserChoices(String s) {
        if (schemaExclusionList.contains(s))
            return true;
        return false;
    }

    /**
     * Evaluates if the currentDBCI is complete enough that we could attempt a connection to lookup
     * values.
     * 
     * @return true if we have all the pieces to connect, false otherwise
     */
    protected boolean couldLookup() {

        if ((currentDBCI.getHostString().length() > 0) && (currentDBCI.getPortString().length() > 0)
                && (currentDBCI.getUserString().length() > 0) && (currentDBCI.getPassString().length() > 0)
                && (currentDBCI.getDbString().length() > 0))
            return (true);
        // One or more are not set
        return (false);
    }

    /**
     * Evaluates if the currentDBCI is complete enough that
     * we could attempt a connection
     * 
     * @return true if we have all the pieces to connect, false otherwise
     */
    protected boolean couldConnect() {

        if ((currentDBCI.getHostString().length() > 0) && (currentDBCI.getPortString().length() > 0)
                && (currentDBCI.getUserString().length() > 0) && (currentDBCI.getPassString().length() > 0)
                && (currentDBCI.getDbString().length() > 0)) {

            if (!dbmsUsesSchema())
                // All are set and we don't use schema
                return (true);
            // Need a schema and have one
            if (currentDBCI.getSchemaString().length() > 0)
                return (true);
            // Need schema but don't have one.
            return (false);
        }
        // One or more are not set
        return (false);
    }

    /**
     * Activates the 'Lookup' button.
     */
    protected void canNowLookup() {
        lookupBtnWgt.setEnabled(true);
    }

    /**
     * Activates the 'Connect' button, and implicitly the 'Lookup' button.
     */
    protected void canNowConnect() {
        canNowLookup();
        connectBtnWgt.setEnabled(true);
    }

    /**
     * This method will run the provided activity using the
     * wizard page progress bar; and wait for the result to
     * complete.
     * <p>
     * If anything goes wrong the message will be shown to the user
     * 
     * @param activity
     */
    protected void runInPage(final IRunnableWithProgress activity) {
        // on a technical level I am not sure which one of these we should use
        //
        boolean guess = true;
        try {
            if (guess) {
                // This is what I think PostGIS wizard page does
                getContainer().run(false, true, activity);
            } else {
                // This is what the origional wizard pages did
                // note the use of an internal blocking call to run the activity
                // and wait for it to complete?
                //
                getContainer().run(false, true, new IRunnableWithProgress() {
                    public void run(IProgressMonitor monitor)
                            throws InvocationTargetException, InterruptedException {
                        PlatformGIS.runBlockingOperation(activity, monitor);
                    }
                });
            }
        } catch (InvocationTargetException e2) {
            // log the error
            CatalogUIPlugin.log(e2.getLocalizedMessage(), e2);
            // tell the user
            setErrorMessage(e2.getCause().getLocalizedMessage());

            // preferences.performDefaults();
        } catch (InterruptedException e2) {
            // user got tired of waiting ...
        }
    }

    // CONTRACT METHODS
    /**
     * Method required by the IDialogPage implementation contract.
     */
    @Override
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        // TODO: is this needed, e.g. for return after <back< and >forward>
        hostTextWgt.setFocus();
    }

    /**
     * Method provided by the DataStoreWizardPage class. TODO: The method currently always returns
     * false; it is probably better to leave it to the subclass to implement it since the compiler
     * will catch the missing method.
     */
    @Override
    public boolean isPageComplete() {
        // For this abstract class, we always return false.
        return false;
    }

    /**
     * Called by the Wizard to instantiate the page and draw the GUI.
     * 
     * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
     * @param parent
     */
    public void createControl(Composite comp) {

        /* ****************************************************************** */
        /* Create the GUI */
        /* ****************************************************************** */
        // GUI FIELDS
        // Constants for layout:
        int WIZARD_PARAM_INDENT = 100; // How far from the left the text fields
        // start.
        int WIZARD_COLUMN_SEPARATION = 20; // The space between the columns
        int WIZARD_CONNECT_NEG_INDENT = -142; // How far from the right the
        // status text starts
        // Repeatedly reused variables.
        FormData fd;
        Label lbl;

        // Defensively build a new Composite eventhough arg0 already is one
        Composite topComp = new Composite(comp, SWT.NULL);
        FormLayout topLayout = new FormLayout();
        topLayout.marginWidth = 0;
        topLayout.marginHeight = 0;
        topComp.setLayout(topLayout);

        // Stored settings: show only if we have some storage.
        if (storedDBCIList.size() > 0) {
            // create the combo
            lbl = new Label(topComp, SWT.NONE);
            lbl.setText(Messages.DataBaseRegistryWizardPage_label_recent_text);
            lbl.setToolTipText(Messages.DataBaseRegistryWizardPage_recent_tooltip);
            fd = new FormData();
            fd.top = new FormAttachment(0, 10);
            fd.left = new FormAttachment(0, 24);
            lbl.setLayoutData(fd);
            rcntComboWgt = new Combo(topComp, SWT.NULL | SWT.READ_ONLY);
            rcntComboWgt.select(0);
            rcntComboWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_recent_tooltip);
            fd = new FormData();
            fd.top = new FormAttachment(0, 10);
            fd.left = new FormAttachment(lbl, 5);
            fd.right = new FormAttachment(100, -40);
            rcntComboWgt.setLayoutData(fd);
        }

        // Composite to hold the parameter widgets
        Composite paramComp = new Composite(topComp, SWT.NULL);
        fd = new FormData();
        if (0 < storedDBCIList.size()) {
            fd.top = new FormAttachment(rcntComboWgt, 10);
        } else {
            fd.top = new FormAttachment(0, 2);
        }
        fd.left = new FormAttachment(topComp, 2);
        fd.bottom = new FormAttachment(100, -2);
        paramComp.setLayoutData(fd);
        paramComp.setLayout(new FormLayout());

        // Host
        lbl = new Label(paramComp, SWT.NULL);
        lbl.setText(Messages.DataBaseRegistryWizardPage_label_host_text);
        lbl.setToolTipText(Messages.DataBaseRegistryWizardPage_host_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(rcntComboWgt, 15);
        fd.left = new FormAttachment(0, 5);
        lbl.setLayoutData(fd);
        hostTextWgt = new Text(paramComp, SWT.BORDER);
        hostTextWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_host_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(rcntComboWgt, 15);
        fd.left = new FormAttachment(0, WIZARD_PARAM_INDENT);
        fd.right = new FormAttachment(100, -5);
        hostTextWgt.setLayoutData(fd);

        // Port
        lbl = new Label(paramComp, SWT.NULL);
        lbl.setText(Messages.DataBaseRegistryWizardPage_label_port_text);
        lbl.setToolTipText(Messages.DataBaseRegistryWizardPage_port_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(hostTextWgt, 5);
        fd.left = new FormAttachment(0, 5);
        lbl.setLayoutData(fd);
        portTextWgt = new Text(paramComp, SWT.BORDER);
        portTextWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_port_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(hostTextWgt, 5);
        fd.left = new FormAttachment(0, WIZARD_PARAM_INDENT);
        // Could change this to calculate size needed for 5 characters: 65535
        fd.right = new FormAttachment(0, WIZARD_PARAM_INDENT + 60);
        portTextWgt.setLayoutData(fd);

        // User
        lbl = new Label(paramComp, SWT.NULL);
        lbl.setText(Messages.DataBaseRegistryWizardPage_label_username_text);
        lbl.setToolTipText(Messages.DataBaseRegistryWizardPage_username_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(portTextWgt, 5);
        fd.left = new FormAttachment(0, 5);
        lbl.setLayoutData(fd);
        userTextWgt = new Text(paramComp, SWT.BORDER);
        userTextWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_username_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(portTextWgt, 5);
        fd.left = new FormAttachment(0, WIZARD_PARAM_INDENT);
        fd.right = new FormAttachment(100, -5);
        userTextWgt.setLayoutData(fd);

        // Password
        lbl = new Label(paramComp, SWT.NULL);
        lbl.setText(Messages.DataBaseRegistryWizardPage_label_password_text);
        lbl.setToolTipText(Messages.DataBaseRegistryWizardPage_password_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(userTextWgt, 5);
        fd.left = new FormAttachment(0, 5);
        lbl.setLayoutData(fd);
        passTextWgt = new Text(paramComp, SWT.BORDER);
        passTextWgt.setEchoChar(("\u2022").toCharArray()[0]); //$NON-NLS-1$
        passTextWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_password_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(userTextWgt, 5);
        fd.left = new FormAttachment(0, WIZARD_PARAM_INDENT);
        fd.right = new FormAttachment(100, -5);
        passTextWgt.setLayoutData(fd);

        // Lookup Button
        lookupBtnWgt = new Button(paramComp, SWT.PUSH);
        lookupBtnWgt.setText(Messages.DataBaseRegistryWizardPage_button_lookup_text);
        lookupBtnWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_button_lookup_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(passTextWgt, 20);
        fd.right = new FormAttachment(100, -5);
        lookupBtnWgt.setLayoutData(fd);

        // Database
        lbl = new Label(paramComp, SWT.NULL);
        lbl.setText(Messages.DataBaseRegistryWizardPage_label_database_text);
        lbl.setToolTipText(Messages.DataBaseRegistryWizardPage_database_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(passTextWgt, 5);
        fd.left = new FormAttachment(0, 5);
        lbl.setLayoutData(fd);
        dbComboWgt = new Combo(paramComp, SWT.BORDER);
        dbComboWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_database_tooltip);
        fd = new FormData();
        fd.left = new FormAttachment(0, WIZARD_PARAM_INDENT);
        fd.top = new FormAttachment(passTextWgt, 5);
        fd.right = new FormAttachment(lookupBtnWgt, -5);
        dbComboWgt.setLayoutData(fd);

        // Schema
        lbl = new Label(paramComp, SWT.NULL);
        lbl.setText(Messages.DataBaseRegistryWizardPage_label_schema_text);
        lbl.setToolTipText(Messages.DataBaseRegistryWizardPage_schema_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(dbComboWgt, 5);
        fd.left = new FormAttachment(0, 5);
        lbl.setLayoutData(fd);
        schemaComboWgt = new Combo(paramComp, SWT.BORDER);
        schemaComboWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_schema_tooltip);
        fd = new FormData();
        fd.top = new FormAttachment(dbComboWgt, 5);
        fd.left = new FormAttachment(0, WIZARD_PARAM_INDENT);
        fd.right = new FormAttachment(lookupBtnWgt, -5);
        schemaComboWgt.setLayoutData(fd);
        if (!dbmsUsesSchema()) {
            lbl.setVisible(false);
            schemaComboWgt.setVisible(false);
        }

        // Advanced section
        // First, create the Advanced Settings Group by calling the method
        // in the concrete class
        advancedGrp = createAdvancedControl(paramComp);

        // If the group exists, make the button and create the group
        if (null != advancedGrp) {
            // Add the Check Button
            advancedBtnWgt = new Button(paramComp, SWT.CHECK);
            advancedBtnWgt.setText(Messages.DataBaseRegistryWizardPage_label_advanced_text);
            advancedBtnWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_label_advanced_tooltip);
            fd = new FormData();
            fd.top = new FormAttachment(dbComboWgt, 45);
            fd.left = new FormAttachment(0, 5);
            advancedBtnWgt.setLayoutData(fd);
            advancedBtnWgt.setSelection(false);
            advancedBtnWgt.addSelectionListener(this);

            // Lay out the Group
            FormData d = new FormData();
            d.top = new FormAttachment(dbComboWgt, 45);
            d.left = new FormAttachment(0, 5);
            d.right = new FormAttachment(100, -5);
            advancedGrp.setLayoutData(d);
            //            
            // //Hide and turn off the Group
            advancedGrp.setVisible(false);// hide it - show with button click
            advancedGrp.setEnabled(false);// turn off - we don't want events
        }

        // Connection Button:
        connectBtnWgt = new Button(topComp, SWT.PUSH);
        connectBtnWgt.setText(Messages.DataBaseRegistryWizardPage_button_connect_text);
        connectBtnWgt.setToolTipText(Messages.DataBaseRegistryWizardPage_button_connect_tooltip);
        fd = new FormData();
        fd.left = new FormAttachment(paramComp, 10);
        // fd.right = new FormAttachment(100,-130);
        fd.bottom = new FormAttachment(100, 0);
        connectBtnWgt.setLayoutData(fd);

        // Strech the paramGrp to take all the space
        ((FormData) paramComp.getLayoutData()).right = new FormAttachment(100,
                WIZARD_CONNECT_NEG_INDENT - WIZARD_COLUMN_SEPARATION);

        /* ****************************************************************** */
        /* Populate the GUI */
        /* ****************************************************************** */

        // If there are stored valid connections, add them to the Combo Widget
        // TODO: This should be limited to only n recent connections
        if (null != storedDBCIList) {
            for (DataBaseConnInfo dbci : storedDBCIList) {
                rcntComboWgt.add(dbci.toDisplayString());
            }
        }
        // Populate the rest of the widgets with the current values which are
        // the
        // defaults which were set in the constructor of the extending class.
        // Note we hide from the user the default database and schema if these
        // are not to be picked as the databases to work against eventhough we
        // leave them as usable for the lookup connection.
        currentDBCI.treatEmptyStringAsNull(false);
        hostTextWgt.setText(currentDBCI.getHostString());
        portTextWgt.setText(currentDBCI.getPortString());
        userTextWgt.setText(currentDBCI.getUserString());
        passTextWgt.setText(currentDBCI.getPassString());
        String str = null;
        str = currentDBCI.getDbString();
        if (!excludeDbFromUserChoices(str))
            dbComboWgt.setText(str);
        if (dbmsUsesSchema()) {
            str = currentDBCI.getSchemaString();
            if (!excludeSchemaFromUserChoices(str))
                schemaComboWgt.setText(str);
        }

        /* ****************************************************************** */
        /* Configure focus and enablement */
        /* ****************************************************************** */
        if (null != rcntComboWgt)
            rcntComboWgt.setFocus();
        else
            hostTextWgt.setFocus();

        if (couldConnect()) {
            lookupBtnWgt.setEnabled(true);
            connectBtnWgt.setEnabled(true);
        } else {
            lookupBtnWgt.setEnabled(false);
            connectBtnWgt.setEnabled(false);
        }

        /* ****************************************************************** */
        /* Hook up the Event Handlers */
        /* ****************************************************************** */

        // Add the Focus listeners
        hostTextWgt.addFocusListener(this);
        portTextWgt.addFocusListener(this);
        userTextWgt.addFocusListener(this);
        passTextWgt.addFocusListener(this);
        dbComboWgt.addFocusListener(this);
        schemaComboWgt.addFocusListener(this);

        // Add the Modify listeners: Store edits after each modification
        if (null != rcntComboWgt)
            rcntComboWgt.addModifyListener(this);
        hostTextWgt.addModifyListener(this);
        portTextWgt.addModifyListener(this);
        userTextWgt.addModifyListener(this);
        passTextWgt.addModifyListener(this);
        dbComboWgt.addModifyListener(this);
        schemaComboWgt.addModifyListener(this);

        // Selection events: connect to DB for lookup or connection
        lookupBtnWgt.addSelectionListener(this);
        connectBtnWgt.addSelectionListener(this);
        // advancedBtnWgt .addSelectionListener(this); //Done above!

        /* ****************************************************************** */
        /* Hook up Tab Traversal */
        /* ****************************************************************** */
        // This currently doesn't work because we have widgets in different
        // trees (not sure that's the reason it is broken).
        // Focus currently follows the default pattern of the order of addition
        // of the widgets plus the occaisional setFocus() methods which can
        // be found with a simple text search.
        // Code left here for any future coder wishing to be brave.
        // List<Control> tablist=new LinkedList<Control>();
        // tablist.add(rcntComboWgt);
        // tablist.add(hostTextWgt);
        // tablist.add(portTextWgt);
        // tablist.add(userTextWgt);
        // tablist.add(passTextWgt);
        // tablist.add(dbComboWgt);
        // if( schemaComboWgt!=null )
        // tablist.add(schemaComboWgt);
        // if( advancedGrp!=null ){
        // tablist.add(advancedBtnWgt);
        // tablist.add(advancedGrp);
        // }
        // tablist.add(connectBtnWgt);
        // topComp.setTabList(tablist.toArray(new Control[tablist.size()]));

        /* ****************************************************************** */
        /* Let her rumble */
        /* ****************************************************************** */
        setControl(topComp);
        setPageComplete(true); // used to highlight the finished button
    }

    /**
     * Creates a GUI Group with widgets to set advanced parameters of the connection or, by default,
     * null if there are no advanced settings. Classes extending this abstract class may override
     * this method and both provide the widgets and handle the events.
     * 
     * @param arg0 the parent widget in which the widgets will be added.
     * @return the Group containing the widgets which will be drawn in the 'Advanced' section of the
     *         wizard page or null (the default) if there is none.
     */
    protected Group createAdvancedControl(Composite arg0) {
        return null;

    }

    /**
     * This is the class that will actually obtain the DataSource. It will try and make a connection
     * to ensure this works out, as such it throws an SQLException if it's an odd day of the week or
     * if you squint too hard.
     * 
     * @return A working DataSource for the database. It should not be closed. But it might be if
     *         you are unlucky.
     */
    protected abstract DataSource getDataSource() throws Exception;

    // LOOKUP METHODS
    /**
     * This method is called in response to selection of the lookup button and gets the names of the
     * available databases on the DBMS server. Instead of overriding this method it is better to
     * override the getDatabaseResultSet method if a custom way of getting the database names is
     * needed
     * 
     * @param con the java.sql.Connection returned by getConnection()
     * @return An array of Strings containing the names of only the databases available on the server
     *         which are suitable for display to the user.
     */
    protected String[] lookupDbNamesForDisplay(DataSource dataSource) {
        java.util.List<String> dbList = new ArrayList<String>();
        Connection con = null;
        try {
            con = dataSource.getConnection();
            ResultSet rs = null;
            if (con != null) {
                rs = getDatabaseResultSet(con);
                while (rs.next()) {
                    String dbName = rs.getString(1);
                    if (!excludeDbFromUserChoices(dbName)) {
                        dbList.add(dbName);
                    }
                }
            }
            return dbList.toArray(new String[dbList.size()]);
        } catch (SQLException e) {
            setMessage(Messages.DataBaseRegistryWizardPage_databaseMessage);
            setErrorMessage(e.getLocalizedMessage());
            return null;
        } finally {
            if (con != null) {
                try {
                    con.close(); // return to pool
                } catch (SQLException e) {
                    // closing anyways
                }
            }
        }
    }

    /**
     * This method can is called so that diffrent databases can provied their own method of
     * obtaining the list of databases without overriding the lookupDbNamesForDisplay method.
     * 
     * @param c the java.sql.Connection returned by getConnection()
     * @return A ResultSet that contains the Database names, for this connection.
     */
    protected ResultSet getDatabaseResultSet(Connection c) throws SQLException {
        return c.getMetaData().getCatalogs();
    }

    /**
     * This method is called in response to selection of the lookup button and gets the names of the
     * available schemata on the DBMS server. Like lookupDbNameForDisplay it is better to avoid
     * overiding this method if a database specific implementation is needed. Instead overide
     * getSchemaResultSet WARNING: This should never be called if !dbmsUsesSchema().
     * 
     * @param con the java.sql.Connection object returned by getConnection()
     * @return An array of Strings containing the names of the schemata available on the server.
     */
    protected String[] lookupSchemaNamesForDisplay(DataSource dataSource) {
        if (dataSource == null) {
            return null; // not connected
        }
        Connection con = null;
        java.util.List<String> schemaList = new ArrayList<String>();
        try {
            con = dataSource.getConnection();
            ResultSet rs = null;
            if (con != null) {
                rs = getSchemasResultSet(con);
                while (rs.next()) {
                    String schemaName = rs.getString(1);
                    if (!excludeSchemaFromUserChoices(schemaName)) {
                        schemaList.add(schemaName);
                    }
                }
            }
            return schemaList.toArray(new String[schemaList.size()]);
        } catch (SQLException e) {
            setMessage(Messages.DataBaseRegistryWizardPage_schemaMessage);
            setErrorMessage(e.getLocalizedMessage());
            return null;
        } finally {
            if (con != null) {
                try {
                    con.close(); // return to pool
                } catch (SQLException e) {
                    // we are closing anyways - ignore
                }
            }
        }
    }

    /**
     * This method can is called so that diffrent databases can provied their own method of
     * obtaining the list of schemas without overriding the lookupSchemasNamesForDisplay method.
     * 
     * @param c the java.sql.Connection returned by getConnection()
     * @return A ResultSet that contains the Schema names, for this connection.
     */
    protected ResultSet getSchemasResultSet(Connection c) throws SQLException {
        return c.getMetaData().getSchemas();
    }

    // EVENT HANDLING METHODS
    /**
     * The focusGained method is called when input focus passes to one of the widgets in the page,
     * following the standard FocusListener contract. If we need to distinguish internal changes of
     * focus from changes of focus involving other programs, such as if the user wanders off to read
     * about the GNU project in her browser and then comes back, we compare the widget which lost
     * focus, saved when handling the focusLost event, to the widget for which this event has been
     * generated. In this case we ignore any focusGain events for widgets which just had the focus;
     * such widgets should still be in the correct state. We no longer trigger connections or
     * validation on focusEvents because of this uncertainty. TODO: Gain of focus on text widgets
     * merely pre-selects the text for deletion if the user inputs new text.
     * 
     * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
     * @param e the event object describing the action that triggered this call
     */
    public void focusGained(FocusEvent e) {

        // Catch the situation where we are disposed between the event being
        // fired and this handler.
        if (null == e.widget) {
            return;
        }

        // We ignore focusGain events on widgets that have just lost focus
        // because this generally means that the focus wandered to another
        // program and has now come back.
        // This also happens when focus returns to the Text field of a Combo
        // widget after the user has interacted with the dropDown portion of
        // that widget.
        if (e.widget == wgtLostFocus)
            return;

    }

    /**
     * The focusLost method is called when input focus leaves one of the widgets in our page,
     * following the standard FocusListener contract. Note that loss of focus does not necessarily
     * imply the user has to work on another widget but may be due to a temporary move to another
     * part of the operating system---the user's mouse could have slipped onto another window or
     * they could be checking email. We no longer trigger connections or validation on focusEvents
     * because of this uncertainty.
     * 
     * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
     * @param e the event (and widget via e.widget) generated for the focus change.
     */
    public void focusLost(FocusEvent e) {

        // Catch the situation where we are disposed between the event being
        // fired and this handler.
        if (null == e.widget) {
            return;
        }

        // Saved in order to be able to ignore focusGain events on widgets
        // which just lost focus.
        // That will happen for focus changes to other programs.
        // This will also happen when focus leaves the Text field of a Combo
        // widget as the user opens up the dropDown portion of the Combo.
        wgtLostFocus = e.widget;

    }

    /**
     * The verifyText method is called prior to modification of the text content in any widget with
     * a Text component, notably the Text and Combo widgets, following the standard verifyListener
     * contract. TODO: Activate this to make verification work. Re-design it based on exclusion
     * lists of characters and strings. The method is used to validate user provided input. The user
     * may change the text character-by-character if they are typing, or may change a whole string
     * through select then delete, by pasting, or by selecting an entry in a drop down Combo. The
     * method works by exclusion which will allow sub-classes to become more restrictive according
     * to their particular rules. This class should therefore be permissive, excluding only
     * characters which are obviously wrong. Extending classes can override this method, starting
     * with a call to this method, i.e. super.verifyText(ve), and then continue with their own, more
     * restrictive, assessment.
     * 
     * @param ve the VerifyEvent object representing the action which triggered the method call.
     */
    /*
     * public void verifyText( VerifyEvent ve) { // Host name: alphanum plus . - if (ve.widget ==
     * host){ ve.doit = ( ( 0 == ve.text.length() ) || Character.isLetterOrDigit(ve.character) ||
     * '.' == ve.character || '-' == ve.character ); } //Port number: only uses digits and
     * non-characters e.g. bksp or del // Handle "" also if (ve.widget == port){ ve.doit = ( (0 ==
     * ve.text.length() ) || Character.isDigit(ve.character) ); return; } //User name: if (ve.widget
     * == user){ return; } //Password is not examined because can be almost anything //Database
     * name: if (ve.widget == database){ return; } //Schema name: if (ve.widget == schema){ return;
     * } }
     */
    /**
     * The modifyText method is called by the event handling mechanism for any widget with a Text
     * field, notably Text and Combo widgets, according to the standard ModifyListener contract. We
     * use this method to add the modified contents into the currentDBCI. The text of the
     * modification should already have been verified prior to this method being called. We may add
     * the verification of the whole text field either here or in the verify listener. TODO: add a
     * verification step here to establish that the whole text contents of the widget's Text field
     * are valid. Figure out how to respond if they are not. If any of the connection parameters are
     * altered, we clear the lists of available databases and schemata since they are no longer
     * guaranteed to work but we leave the text as is since the user is working on it. As a last
     * step, we also evaluate if we can now connect, and if so activate the lookup and connect
     * buttons.
     */
    public void modifyText(ModifyEvent e) {

        // Catch the situation where we are disposed between the event being
        // fired and this handler.
        if (null == e.widget) {
            return;
        }

        // SWITCH ON e.widget
        if (e.widget == rcntComboWgt) {
            // set the connection info
            // NOTE: This presumes the two idices are strictly equal. If we make
            // the combo hold only a subset of the stored list, we will
            // have to use a different index.
            int i = rcntComboWgt.getSelectionIndex();
            currentDBCI.setParameters(storedDBCIList.get(i));
            // Set the text info
            hostTextWgt.setText(currentDBCI.getHostString());
            portTextWgt.setText(currentDBCI.getPortString());
            userTextWgt.setText(currentDBCI.getUserString());
            passTextWgt.setText(currentDBCI.getPassString());
            dbComboWgt.setText(currentDBCI.getDbString());
            if (null != schemaComboWgt)
                schemaComboWgt.setText(currentDBCI.getSchemaString());
            canNowConnect();// Implies we can lookup as well
            connectBtnWgt.setFocus(); // Allows the user to pick and hit enter
            // twice.
        }
        if (e.widget == hostTextWgt) {

            // store the modified value
            currentDBCI.setHost(((Text) e.widget).getText());

            // clear the lists of available databases and schemata
            int i = dbComboWgt.getItemCount();
            dbComboWgt.remove(0, i - 1);
            if (dbmsUsesSchema()) {
                int j = schemaComboWgt.getItemCount();
                schemaComboWgt.remove(0, j - 1);
            }

        }
        if (e.widget == portTextWgt) {

            // store the modified value
            currentDBCI.setPort(((Text) e.widget).getText());

            // clear the lists of available databases and schemata
            int i = dbComboWgt.getItemCount();
            dbComboWgt.remove(0, i - 1);
            if (dbmsUsesSchema()) {
                int j = schemaComboWgt.getItemCount();
                schemaComboWgt.remove(0, j - 1);
            }

        }
        if (e.widget == userTextWgt) {

            // store the modified value
            currentDBCI.setUser(((Text) e.widget).getText());

            // clear the lists of available databases and schemata
            int i = dbComboWgt.getItemCount();
            dbComboWgt.remove(0, i - 1);
            if (dbmsUsesSchema()) {
                int j = schemaComboWgt.getItemCount();
                schemaComboWgt.remove(0, j - 1);
            }

        }
        if (e.widget == passTextWgt) {

            // store the modified value
            currentDBCI.setPass(((Text) e.widget).getText());

            // clear the lists of available databases and schemata
            int i = dbComboWgt.getItemCount();
            dbComboWgt.remove(0, i - 1);
            if (dbmsUsesSchema()) {
                int j = schemaComboWgt.getItemCount();
                schemaComboWgt.remove(0, j - 1);
            }

        }
        if (e.widget == dbComboWgt) {

            // store the modified value
            currentDBCI.setDb(((Combo) e.widget).getText());

        }
        if (dbmsUsesSchema()) {

            // store the modified value
            if (e.widget == schemaComboWgt) {
                currentDBCI.setSchema(((Combo) e.widget).getText());
            }

        }

        // At end, activate lookup and connect buttons if there is enough
        // info to try. Either we could connect, in which case we will
        // activate both the connect and the lookup buttons, or we might
        // be able to lookup only.
        if (couldConnect()) {
            canNowConnect();
        } else if (couldLookup()) {
            canNowLookup();
        }

    }

    /**
     * The method called by the event handling mechanism for any regular (i.e. not 'default)
     * selection event on any widget to which this class was added as a SelectionListener. The only
     * widgets we care about are the button widgets. Text and Combo widgets will receive
     * modifyEvents for any changes to their contents so we handle their entries in the
     * modifyText(..) method.
     * 
     * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
     * @see #widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
     * @param e the SelectionEvent which includes e.widget, the widget generating the event
     */
    public void widgetSelected(SelectionEvent e) {
        // Catch the situation where we are disposed between the event being
        // fired and this handler being called.
        if (null == e.widget) {
            return;
        }

        // SWITCH on widget

        if (e.widget.equals(advancedBtnWgt)) {
            boolean b = advancedBtnWgt.getSelection();
            advancedGrp.setVisible(b);
            advancedGrp.setEnabled(b);
        }

        if (e.widget.equals(lookupBtnWgt)) {

            // Trap a spurious second click, re-enable at end
            // Ofcourse this is a race condition so the trap might not work
            lookupBtnWgt.setEnabled(false);

            // Get a connection for the lookup
            DataSource dataSource = null;

            // This check should always be true, because we should check before
            // calling the method. Note, we catch a 'false' here in the next
            // statement below since 'con' will remain 'null'.
            if (couldConnect()) {
                try {
                    dataSource = getDataSource();
                } catch (Exception ex) {
                    // Log the error
                    CatalogUIPlugin.log(ex.getLocalizedMessage(), ex);
                    // Set the error in the animated area of the Dialog
                    setErrorMessage(ex.getLocalizedMessage());
                }
            }

            // Did we fail? If so, bail out
            if (dataSource == null) {
                // Re-enable the lookup button
                // e.g user now starts the server, wants to connect
                lookupBtnWgt.setEnabled(true);

                return;

            }

            // By here, the connection has succeeded, it is non-null.

            // Reset any previous error messages
            setErrorMessage(null);

            // Get the database names suitable for display to the user
            // Logic is in a separate method to be easy to override by extendors
            String[] arr = lookupDbNamesForDisplay(dataSource);
            // Set the database names in the dbComboWgt
            if (null != arr) {
                dbComboWgt.setItems(arr);
                dbComboWgt.select(0);
            }

            // If needed, get the schema names and set them in the
            // schemaComboWgt
            // Logic is in a separate method to be easy to override by extendors
            if (dbmsUsesSchema()) {
                arr = lookupSchemaNamesForDisplay(dataSource);
                if (null != arr) {
                    schemaComboWgt.setItems(arr);
                    schemaComboWgt.select(0);
                }
            }

            // Set focus on the database list: the user may want to pick a new
            // db
            dbComboWgt.setFocus();

            // Close the connection used for lookup
            if (dataSource != null) {
                // dataSource.close();
            }

            // Re-enable the lookup widget
            // This allows the user can try again, for example, if the server
            // has changed in the meantime.
            lookupBtnWgt.setEnabled(true);

            return;
        }

        if (e.widget.equals(connectBtnWgt)) {

            // Trap a spurious second click; disable & re-enable if we fail
            connectBtnWgt.setEnabled(false);

            // TODO: check first if we are connected; if so return (or
            // disconnect?)
            // Look in java.net for functionality (see error message on failure)

            if (!couldConnect()) {
                // This should never happen since the connect button should not
                // be activated if we don't have the info needed to connect.
                // Leave the button inactive.
                return;
            }

            // Try to connect
            DataSource dataSource = null;
            try {
                dataSource = getDataSource();
            } catch (Exception ex) {
                // Log the error
                CatalogUIPlugin.log(ex.getLocalizedMessage(), ex);
                // Set the error in the animated area of the Dialog
                setErrorMessage(ex.getLocalizedMessage());
            }
            // Did we fail?
            if (dataSource == null) {
                // Failed to connect.
                // Reset the dialog: the user may go launch the Db server.
                connectBtnWgt.setEnabled(true);
                return;
            }
            // By here, the connection is ok

            // Reset any previous error messages
            setErrorMessage(null);

            // Activate Finish Button
            getWizard().getContainer().updateButtons();

            // Append the successful connection to the stored list
            if (!storedDBCIList.contains(currentDBCI)) {
                DataBaseConnInfo dbci = new DataBaseConnInfo(""); //$NON-NLS-1$
                dbci.setParameters(currentDBCI);
                storedDBCIList.add(dbci);
            }

            // Store all connection parameters
            int s = storedDBCIList.size();
            java.util.List<String> rec = new ArrayList<String>(s);
            for (DataBaseConnInfo i : storedDBCIList) {
                rec.add(i.toString());
            }
            settings.put(settingsArrayName, rec.toArray(new String[s]));

            // Reset the dialog entries
            // NB this will also reset currentDBCI through the modify listener
            // TODO: move this elsewhere since it's ugly to see the values
            // unset prior to clicking the 'Finish' button
            // not to mention very very very confusing
            // XXX: Comented this section out because of the above "todo"

            /*
             * hostTextWgt.setText(defaultDBCI.getHostString());
             * portTextWgt.setText(defaultDBCI.getPortString());
             * userTextWgt.setText(defaultDBCI.getUserString());
             * passTextWgt.setText(defaultDBCI.getPassString()); // These two lines don't seem
             * necessary but should be and do no harm dbComboWgt.removeAll();
             * schemaComboWgt.removeAll(); if (!excludeDbFromUserChoices(defaultDBCI.getDbString()))
             * dbComboWgt.setText(defaultDBCI.getDbString()); if (null != schemaComboWgt) if
             * (!excludeSchemaFromUserChoices(defaultDBCI.getSchemaString()))
             * schemaComboWgt.setText(defaultDBCI.getSchemaString());
             */

        }

    }

    /**
     * The method called by the event handling mechanism for any 'default' selection event on any
     * widget to which this class was added as a SelectionListener. There is nothing to do here. The
     * widgetDefaultSelected method is called only in the Text and Combo widgets when the <enter>
     * key is typed while focus is on the Text field. Since changes to the text field all generate
     * the modifyEvent as well, we will handle modifications in the modifyText(..) method and can do
     * nothing here.
     * 
     * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
     * @see #widgetSelected(org.eclipse.swt.events.SelectionEvent)
     * @param e
     */
    public void widgetDefaultSelected(SelectionEvent e) {

        return;

        // Catch the situation where we are disposed between the event being
        // fired and this handler.
        // if (null == e.widget){
        // return;
        // }

    }

    public void dispose() {
        if (dataSource != null) {
            try {
                dataSource.close();
            } catch (SQLException e) {
                // couldn't close connection, no matter -- we are exiting
            }
        }
        super.dispose();
    }

}