Package org.openquark.gems.client.generators

Source Code of org.openquark.gems.client.generators.DatabaseTableGemGenerator$DatabaseTableGemGeneratorDialog$DatabaseTableGemGeneratorCardStack

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/


/*
* DatabaseTableGemGenerator.java
* Creation date: May 6, 2004
* By: Richard Webster
*/
package org.openquark.gems.client.generators;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.openquark.cal.compiler.ModuleTypeInfo;
import org.openquark.cal.compiler.Scope;
import org.openquark.cal.compiler.TypeChecker;
import org.openquark.cal.compiler.TypeConstructor;
import org.openquark.cal.compiler.TypeExpr;
import org.openquark.cal.compiler.SourceModel.ModuleDefn;
import org.openquark.cal.module.Cal.Collections.CAL_List;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
import org.openquark.cal.module.Cal.Data.CAL_DataGems;
import org.openquark.cal.module.Cal.Data.CAL_Sql;
import org.openquark.cal.services.GemEntity;
import org.openquark.cal.services.GemFilter;
import org.openquark.cal.services.GemViewer;
import org.openquark.cal.services.IdentifierUtils;
import org.openquark.cal.services.Perspective;
import org.openquark.cal.valuenode.Target;
import org.openquark.cal.valuenode.ValueNode;
import org.openquark.gems.client.ValueRunner;
import org.openquark.gems.client.valueentry.ValueEditorManager;
import org.openquark.util.UnsafeCast;
import org.openquark.util.datadictionary.ValueType;
import org.openquark.util.ui.WizardBase;
import org.openquark.util.ui.WizardCard;
import org.openquark.util.ui.WizardCardStack;


/**
* A gem generator for creating strongly-typed database table records.
* @author Richard Webster
*/
public class DatabaseTableGemGenerator implements GemGenerator {
   
    /** The icon to use for the generator. */
    private static final Icon GENERATOR_ICON = new ImageIcon(GemGenerator.class.getResource("/Resources/supercombinator.gif"));

    /**
     * @see org.openquark.gems.client.generators.GemGenerator#launchGenerator(javax.swing.JFrame, org.openquark.cal.services.Perspective, org.openquark.gems.client.ValueRunner, org.openquark.gems.client.valueentry.ValueEditorManager, org.openquark.cal.compiler.TypeChecker)
     */
    public GemGenerator.GeneratedDefinitions launchGenerator(JFrame parent,
                                                         Perspective perspective,
                                                         ValueRunner valueRunner,
                                                         ValueEditorManager valueEditorManager,
                                                         TypeChecker typeChecker) {
        if (parent == null || perspective == null) {
            throw new NullPointerException();
        }

        final DatabaseTableGemGeneratorDialog generatorUI = new DatabaseTableGemGeneratorDialog(parent, perspective, valueRunner);

        generatorUI.doModal();
        return new GemGenerator.GeneratedDefinitions() {

            public ModuleDefn getModuleDefn() {
                return null;
            }

            public Map<String, String> getSourceElementMap() {
                return generatorUI.getSourceDefinitions();
            }
        };
    }

    /**
     * @see org.openquark.gems.client.generators.GemGenerator#getGeneratorMenuName()
     */
    public String getGeneratorMenuName() {
        return GeneratorMessages.getString("DBTableGF_FactoryMenuName");
    }

    /**
     * @see org.openquark.gems.client.generators.GemGenerator#getGeneratorTitle()
     */
    public String getGeneratorTitle() {
        return GeneratorMessages.getString("DBTableGF_FactoryTitle");
    }

    /**
     * @see org.openquark.gems.client.generators.GemGenerator#getGeneratorIcon()
     */
    public Icon getGeneratorIcon() {
        return GENERATOR_ICON;
    }

    /**
     * This is the user interface class for the Database Tables gem generator.
     * @author Richard Webster
     */
    private static class DatabaseTableGemGeneratorDialog extends WizardBase {

        private static final long serialVersionUID = -9142879910177397417L;

        /** The perspective this UI is running in. */
        private final Perspective perspective;

        /** A value runner for running simple CAL programs. */
        private final ValueRunner valueRunner;

        /** This state is the information collected by the wizard. */
        private final TableWizardState wizardState = new TableWizardState();

        /**
         * Constructor for a new generator ui.
         * @param parent       the parent of the dialog
         * @param perspective  the perspective the UI should use
         * @param valueRunner  a value runner for executing CAL code
         */
        public DatabaseTableGemGeneratorDialog(JFrame parent,
                                    Perspective perspective,
                                    ValueRunner valueRunner) {
            super(parent, GeneratorMessages.getString("DBTableGF_CreateDbTableGemsTitle"));

            if (perspective == null || valueRunner == null) {
                throw new NullPointerException();
            }

            this.perspective = perspective;
            this.valueRunner = valueRunner;
        }

        /**
         * @see org.openquark.util.ui.WizardBase#makeCardStack()
         */
        @Override
        protected WizardCardStack makeCardStack () {
            return new DatabaseTableGemGeneratorCardStack();
        }


        /**
         * Returns the ValueNode corresponding to the specified value expression, or null if it is not valid.
         */
        private ValueNode getValueNodeFromCode(String valueText) {
            // Now create a target to be run by a value runner, and return the result.
            Target valueTarget = new Target.SimpleTarget(valueText);

            try {
                return valueRunner.getValue (valueTarget, perspective.getWorkingModuleName());
            } catch (Exception e) {
                e.printStackTrace ();
                return null;
            }
        }

        /**
         * Runs the specified code and returns the result as a Java Object.
         */
        private Object getObjectFromCode(String code) {
            ValueNode vn = getValueNodeFromCode(code);
            return (vn == null) ? null : vn.getValue();
        }

        /**
         * Runs the specified code and returns the list result.
         * Returns an empty list if the result is not a list.
         */
        private List<?> getListFromCode(String code) {
            Object obj = getObjectFromCode(code);
            return (obj instanceof List<?>) ? (List<?>) obj : Collections.EMPTY_LIST;
        }

        /**
         * A card stack for this wizard.
         */
        private class DatabaseTableGemGeneratorCardStack extends WizardCardStack {
            private static final long serialVersionUID = -8407335721996562142L;

            DatabaseTableGemGeneratorCardStack() {
                addCard(new GeneralInfoCard(wizardState));
                addCard (new SelectTablesCard(wizardState));
//                addCard (new CustomizeTableGemsCard(wizardState));

                finishInit ();
            }
        }

        /**
         * @return the new source definitions that should be created
         */
        public Map<String, String> getSourceDefinitions() {
            Map<String, String> sourceDefinitions = new LinkedHashMap<String, String>();
            Set<String> tableGemNamesUsed = new HashSet<String>();

            for (final String tableName : wizardState.tables) {
                // Determine the name of the gem for this table.
                // Make sure it is unique.
                String tableGemName = makeTableGemName(tableName, tableGemNamesUsed);
                if (tableGemName == null || tableGemName.length() == 0) {
                    continue;
                }
                tableGemNamesUsed.add(tableGemName);

                String tableGemSourceBody = buildTableGemSource(tableName);
                if (tableGemSourceBody == null || tableGemSourceBody.length() == 0) {
                    continue;
                }

                StringBuilder source = new StringBuilder(GeneratorMessages.getString("DBTableGF_FunctionDeclComment"));

                if (wizardState.gemComment != null && wizardState.gemComment.trim().length() > 0) {
                    source.append("// " + wizardState.gemComment + "\n");
                }

                // TODO: include a type signature...

                source.append(wizardState.gemScope.toString()).append(' ');               

                source.append(tableGemName);

                // Add the table argument.
                source.append(" table");

                source.append(" = \n");
                source.append(tableGemSourceBody);
                source.append(";\n");

                sourceDefinitions.put(tableGemName, source.toString());
            }

            return sourceDefinitions;
        }

        /**
         * Generates a valid (and unique) gem name based on the table name. 
         * @param tableName          the name of the table
         * @param tableGemNamesUsed  the table gem names already used
         * @return                   a unique and valid name for the table gem
         */
        private String makeTableGemName(String tableName, Set<String> tableGemNamesUsed) {
            String baseRecordGemName = tableName + "TableFields";
            String validGemName = IdentifierUtils.makeIdentifierName(baseRecordGemName);

            // Ensure that the name is unique in the current module and is not already used
            // by one of the other table gems being generated.
            String uniqueGemName = validGemName;
            int counter = 0;
            while (tableGemNamesUsed.contains(uniqueGemName)
                    || perspective.getWorkingModuleTypeInfo().getFunctionalAgent(uniqueGemName) != null) {
                ++counter;
                uniqueGemName = validGemName + counter;
            }

            return uniqueGemName;
        }

        /**
         * Generates the source for the table gem body.
         * @param tableName  the name of the table
         * @return           the code for the body of the table gem
         */
        private String buildTableGemSource(String tableName) {
            // TODO: handle qualified table names...
            // TODO: marshal the list of records directly instead of converting to a tuple once this is implemented for records...
            String fieldInfoCode = CAL_Prelude.Functions.output.getQualifiedName() + " (" + CAL_List.Functions.map.getQualifiedName() + " (\\rec -> (rec.columnName, rec.valueType)) (" + CAL_DataGems.Functions.jdbcGetTableFieldInfo.getQualifiedName() + " " + wizardState.connectionGemName + " \"" + tableName + "\"))";
            List<List<?>> tupleList = UnsafeCast.unsafeCast(getListFromCode(fieldInfoCode));

            // Build the code for each field.
            List /*String[3]*/<String[]> fieldCodeItemsList = new ArrayList<String[]>();
            Set<String> recordFieldNamesUsed = new HashSet<String>();

            for (final List<?> tuple : tupleList) {
                String tableFieldName = (String) tuple.get(0);
                ValueType valueType = (ValueType) tuple.get(1);

                // Get the name of the field gem of the appropriate type.
                String makeFieldGemName = getMakeFieldGem(valueType);

                // Leave out any gems of unrecognized types.
                if (makeFieldGemName == null || makeFieldGemName.length() == 0) {
                    System.out.println("DatabaseTableGemGenerator:  skipping field '" + tableFieldName + "' of type " + valueType.toString() + " as this type is not currently supported.");
                    continue;
                }

                // Find a valid (and unique) name for the field with the record.
                String recordFieldName = makeRecordFieldName(tableFieldName, recordFieldNamesUsed);
                if (recordFieldName == null || recordFieldName.length() == 0) {
                    continue;
                }
                recordFieldNamesUsed.add(recordFieldName);

                fieldCodeItemsList.add(new String[] { recordFieldName, makeFieldGemName, tableFieldName});
            }

            if (fieldCodeItemsList.isEmpty()) {
                return null;
            }

            // Find the longest record field name and the longest makeField gem name.
            int maxFieldNameLength = 0;
            int maxMakeFieldGemNameLength = 0;
            for (final String[] codeParts : fieldCodeItemsList) {
                int recordFieldNameLen = codeParts[0].length();
                if (recordFieldNameLen > maxFieldNameLength) {
                    maxFieldNameLength = recordFieldNameLen;
                }

                int makeFieldGemNameLen = codeParts[1].length();
                if (makeFieldGemNameLen > maxMakeFieldGemNameLength) {
                    maxMakeFieldGemNameLength = makeFieldGemNameLen;
                }
            }

            // Assemble the field code segments into the body of the gem.
            StringBuilder sb = new StringBuilder("    {\n");

            for (int fieldN = 0, nFields = fieldCodeItemsList.size(); fieldN < nFields; ++fieldN) {
                String[] codeParts = fieldCodeItemsList.get(fieldN);

                String recordFieldName = codeParts[0];
                String makeFieldGemName = codeParts[1];
                String databaseFieldName = codeParts[2];

                sb.append("      ");
                sb.append(recordFieldName);
               
                // Add some padding after the record field name so that the code lines up nicely.
                int recordFieldNameLen = recordFieldName.length();
                for (int i = recordFieldNameLen; i < maxFieldNameLength; ++i) {
                    sb.append(' ');
                }

                sb.append(" = ");
                sb.append(makeFieldGemName);

                // Add some padding after the make field gem name so that the code lines up nicely.
                int makeFieldGemNameLen = makeFieldGemName.length();
                for (int i = makeFieldGemNameLen; i < maxMakeFieldGemNameLength; ++i) {
                    sb.append(' ');
                }

                sb.append(" table \"");
                sb.append(databaseFieldName);
                sb.append('\"');

                if (fieldN < nFields - 1) {
                    sb.append(',');
                }
                sb.append('\n');
            }
            sb.append("    }");

            return sb.toString();
        }

        /**
         * Returns the name of the gem which will build a field expression of the specified value type.
         * @param valueType  the field value type
         * @return           the name of the gem which will build a field expression of the specified type, or null if there is none
         */
        private String getMakeFieldGem(ValueType valueType) {
            switch (valueType.value()) {
                case ValueType._stringType :  return CAL_Sql.Functions.stringField.getQualifiedName();
                case ValueType._intType :     return CAL_Sql.Functions.intField.getQualifiedName();
                case ValueType._doubleType :  return CAL_Sql.Functions.doubleField.getQualifiedName();
                case ValueType._booleanType : return CAL_Sql.Functions.booleanField.getQualifiedName();
                case ValueType._timeType :    return CAL_Sql.Functions.timeField.getQualifiedName();
                case ValueType._binaryType :  return CAL_Sql.Functions.binaryField.getQualifiedName();

                case ValueType._nullType :
                default :
                    return null;
            }
        }

        /**
         * Generates a valid (and unique) record field name based on the table field name. 
         * @param tableFieldName        the name of the field in the table
         * @param recordFieldNamesUsed  the record field names already used
         * @return                      a unique and valid name for the record field
         */
        private String makeRecordFieldName(String tableFieldName, Set<String> recordFieldNamesUsed) {
            String validFieldName = IdentifierUtils.makeIdentifierName(tableFieldName);

            // Ensure that the name is not already used by one of the other record fields.
            String uniqueFieldName = validFieldName;
            int counter = 0;
            while (recordFieldNamesUsed.contains(uniqueFieldName)) {
                ++counter;
                uniqueFieldName = validFieldName + counter;
            }

            return uniqueFieldName;
        }

        /**
         * A class to hold the state of the dialog.
         */
        private static class TableWizardState {
            private String gemComment = "";
            private Scope gemScope = Scope.PUBLIC;
            private String connectionGemName = "";
            private final List <String> tables = new ArrayList<String>();
        }

        /**
         * A wizard card for entering general info about the table gems.
         */
        private class GeneralInfoCard extends WizardCard {
            private static final long serialVersionUID = -5973608436858769130L;

            /** The name of this card. */
            static final String CARD_NAME = "GeneralInfo";

            /** The wizard state to be used for this card. */
            private final TableWizardState wizardState;

//            /** The text field for entering the name of the new gem. */
//            private final JTextField gemNameField = new JTextField();
   
            /** The text field for entering the comment for the new gem. */
            private final JTextField commentField = new JTextField();

            /** The radio button for selecting private scope. */
            private final JRadioButton privateButton = new JRadioButton(GeneratorMessages.getString("PrivateLabel"));
   
            /** The radio button for selecting public scope. */
            private final JRadioButton publicButton = new JRadioButton(GeneratorMessages.getString("PublicLabel"));

            /** The button group for the radio buttons. */
            private final ButtonGroup buttonGroup = new ButtonGroup();

            /** The combobox for selecting a connection gem. */
            private final JComboBox connectionGemCombo = new JComboBox(new DefaultComboBoxModel());

            /**
             * Constructor for GeneralInfoCard.
             */
            GeneralInfoCard(TableWizardState wizardState) {
                this.wizardState = wizardState;

                buttonGroup.add(publicButton);
                buttonGroup.add(privateButton);
                buttonGroup.setSelected(publicButton.getModel(), true);
               
                connectionGemCombo.addActionListener(new ActionListener () {
                        public void actionPerformed(ActionEvent e) {
                            cardStateChanged();
                        }
                    });
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getTitle()
             */
            @Override
            protected String getTitle() {
                return GeneratorMessages.getString("DBTableGF_GeneralInfoCardTitle");
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getSubtitle()
             */
            @Override
            protected String getSubtitle() {
                return GeneratorMessages.getString("DBTableGF_GeneralInfoCardSubtitle");
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getCardName()
             */
            @Override
            public String getCardName() {
                return CARD_NAME;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getNextCardName()
             */
            @Override
            protected String getNextCardName () {
                return SelectTablesCard.CARD_NAME;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getMainPanel()
             */
            @Override
            protected JComponent getMainPanel () {
                JPanel javaPanel = new JPanel();

                javaPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
                javaPanel.setLayout(new GridBagLayout());

                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.NORTHWEST;
                constraints.fill = GridBagConstraints.HORIZONTAL;
                constraints.insets = new Insets(5, 5, 5, 5);

//                constraints.gridx = 1;
//                constraints.weightx = 0;
//                constraints.weighty = 0;
//                constraints.gridwidth = 1;
//                javaPanel.add(new JLabel(GemCutter.getResourceString("JGF_GemNameHeader")), constraints);
//
//                constraints.gridx = 2;
//                constraints.weightx = 1;
//                constraints.weighty = 0;       
//                constraints.gridwidth = GridBagConstraints.REMAINDER;
//                gemNameField.setColumns(20);
//                javaPanel.add(gemNameField, constraints);

                constraints.gridx = 1;
                constraints.weightx = 0;
                constraints.weighty = 0;
                constraints.gridwidth = 1;
                javaPanel.add(new JLabel(GeneratorMessages.getString("JGF_CommentHeader")), constraints);

                constraints.gridx = 2;
                constraints.weightx = 1;
                constraints.weighty = 0;       
                constraints.gridwidth = GridBagConstraints.REMAINDER;
//                commentField.setColumns(20);
                javaPanel.add(commentField, constraints);

                constraints.gridx = 1;
                constraints.weightx = 0;
                constraints.weighty = 0;
                constraints.gridwidth = 1;
                javaPanel.add(new JLabel(GeneratorMessages.getString("JGF_VisibilityHeader")), constraints);

                constraints.gridx = 2;
                constraints.weightx = 0;
                constraints.weighty = 0;
                constraints.gridwidth = 1;       
                javaPanel.add(publicButton, constraints);

                constraints.gridx = 3;
                constraints.weightx = 0;
                constraints.weighty = 0;
                constraints.gridwidth = 1;       
                javaPanel.add(privateButton, constraints);

                constraints.gridx = 1;
                constraints.weightx = 0;
                constraints.weighty = 0;
                constraints.gridwidth = 1;
                javaPanel.add(new JLabel(GeneratorMessages.getString("JDBCGF_ConnectionGemNameHeader")), constraints);

                constraints.gridx = 2;
                constraints.weightx = 1;
                constraints.weighty = 0;
                constraints.gridwidth = GridBagConstraints.REMAINDER;
                javaPanel.add(connectionGemCombo, constraints);

                constraints.gridx = 4;
                constraints.weightx = 1;
                constraints.weighty = 0;
                constraints.gridwidth = GridBagConstraints.REMAINDER;
                javaPanel.add(new JLabel(""), constraints);

                return javaPanel;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#initControls()
             */
            @Override
            protected boolean initControls () {
                // Populate the connection gems list, if necessary.
                if (connectionGemCombo.getItemCount() == 0) {
//                    // Add a special option to create a new connection.
//                    connectionGemCombo.addItem("<new>");

                    // Add each available connection gem.
                    List<String> connectionGems = fetchConnectionGemNames();
                    for (final String string : connectionGems) {
                        connectionGemCombo.addItem(string)
                    }
                }

                // Update the controls with the current values.
//                gemNameField.setText(gemName);
                commentField.setText(wizardState.gemComment);

                if (wizardState.gemScope == Scope.PUBLIC) {
                    publicButton.setSelected(true);
                } else {
                    privateButton.setSelected(true);
                }

                connectionGemCombo.setSelectedItem(wizardState.connectionGemName);

                return true;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#commitChanges()
             */
            @Override
            protected boolean commitChanges () {
//                gemName = gemNameField.getText();
                wizardState.gemComment = commentField.getText();
                wizardState.gemScope = publicButton.getModel().isSelected() ? Scope.PUBLIC : Scope.PRIVATE;
                wizardState.connectionGemName = (String) connectionGemCombo.getSelectedItem();

                return true;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#canFinish()
             */
            @Override
            protected boolean canFinish () {
                return false;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getTipInfo()
             */
            @Override
            protected TipInfo getTipInfo () {
                // Check whether a connection gem has been specified.
                String connectionGemName = (String) connectionGemCombo.getSelectedItem();
                if (connectionGemName == null || connectionGemName.length() == 0) {
                    return new TipInfo (WARNING_TIP, GeneratorMessages.getString("DBTableGF_Tip_SelectDatabaseConnection"));
                }

                return new TipInfo (INFO_TIP, GeneratorMessages.getString("DBTableGF_Tip_NextToSelectTables"));
            }

            /**
             * @see org.openquark.util.ui.WizardCard#onFinish()
             */
            @Override
            protected boolean onFinish () {
                return false;
            }

            /**
             * Returns a list of the names of the available connection gems.
             */
            private List <String> fetchConnectionGemNames() {
                TypeConstructor typeConstructor = perspective.getTypeConstructor(CAL_DataGems.TypeConstructors.JDBCConnection);
                final TypeExpr typeExpr = TypeExpr.makeNonParametricType(typeConstructor);

                return fetchGemsOfType(typeExpr);
            }

            /**
             * Returns a list of the names of the gems which have the specified return type and no inputs.
             */
            private List <String> fetchGemsOfType(final TypeExpr returnTypeExpr) {
                GemViewer gemViewer = new GemViewer();
               
                final ModuleTypeInfo moduleTypeInfo = perspective.getWorkingModuleTypeInfo();

                // Create a filter which will find all gems which return the specified type
                // and take no inputs.
                // TODO: add support for gems which do take inputs...
                GemFilter filter = new GemFilter() {
                    @Override
                    public boolean select(GemEntity gemEntity) {
                        TypeExpr gemType = gemEntity.getTypeExpr();
                        return TypeExpr.canPatternMatch(gemType, returnTypeExpr, moduleTypeInfo);
                    }
                };
                gemViewer.addFilter(filter);

                Perspective newPerspective = new Perspective(perspective.getWorkspace(), perspective.getWorkingModule());
                newPerspective.setGemEntityViewer(gemViewer);

                Set<GemEntity> matchingGems = newPerspective.getVisibleGemEntities();

                // Extract the gem names from the list.
                List<String> gemNames = new ArrayList<String>();
                for (final GemEntity gemEntity : matchingGems) {
                    gemNames.add(gemEntity.getName().getQualifiedName());
                }

                return gemNames;
            }
        }

        /**
         * A wizard card for selecting one or more database tables.
         */
        private class SelectTablesCard extends WizardCard {
            private static final long serialVersionUID = 5923107637829194229L;

            /** The name of this card. */
            static final String CARD_NAME = "SelectTables";

            /** The wizard state to be used for this card. */
            private final TableWizardState wizardState;

            /** The connection gem used to fetch the list of tables currently displayed. */
            private String connectionForTables = "";

            /** The list for selecting tables. */
            private final JList tableList = new JList(new DefaultListModel());

            /** A button to select all the tables. */
            private final JButton selectAllButton = new JButton(GeneratorMessages.getString("DBTableGF_SelectAllCaption"));

            /**
             * Constructor for SelectTablesCard.
             */
            SelectTablesCard(TableWizardState wizardState) {
                this.wizardState = wizardState;

                // Allow multiple selection in the list.
                tableList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

                tableList.addListSelectionListener(new ListSelectionListener() {
                        public void valueChanged(ListSelectionEvent e) {
                            cardStateChanged();
                        }
                    });

                selectAllButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                            int nTablesAvailable = tableList.getModel().getSize();
                            int[] selectionIndices = new int[nTablesAvailable];
                            for (int tableN = 0; tableN < nTablesAvailable; ++tableN) {
                                selectionIndices[tableN] = tableN;
                            }
                            tableList.setSelectedIndices(selectionIndices);
                        }
                    });
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getTitle()
             */
            @Override
            protected String getTitle() {
                return GeneratorMessages.getString("DBTableGF_SelectTablesCardTitle");
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getSubtitle()
             */
            @Override
            protected String getSubtitle() {
                return GeneratorMessages.getString("DBTableGF_SelectTablesCardSubtitle");
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getCardName()
             */
            @Override
            public String getCardName() {
                return CARD_NAME;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getNextCardName()
             */
            @Override
            protected String getNextCardName () {
                return null;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getMainPanel()
             */
            @Override
            protected JComponent getMainPanel () {
                JPanel javaPanel = new JPanel();

                javaPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
                javaPanel.setLayout(new GridBagLayout());

                GridBagConstraints constraints = new GridBagConstraints();
                constraints.anchor = GridBagConstraints.NORTHWEST;
                constraints.fill = GridBagConstraints.HORIZONTAL;
                constraints.insets = new Insets(5, 5, 5, 5);

//                constraints.gridx = 1;
//                constraints.weightx = 0;
//                constraints.weighty = 0;
//                constraints.gridwidth = 1;
//                javaPanel.add(new JLabel(GemCutter.getResourceString("JGF_GemNameHeader")), constraints);
//
//                constraints.gridx = 2;
//                constraints.weightx = 1;
//                constraints.weighty = 0;       
//                constraints.gridwidth = GridBagConstraints.REMAINDER;
//                gemNameField.setColumns(20);
//                javaPanel.add(gemNameField, constraints);

//                constraints.gridy = 0;
//                constraints.weightx = 0;
//                constraints.weighty = 0;
//                constraints.gridwidth = 1;
//                javaPanel.add(new JLabel(GemCutter.getResourceString("DBTableGF_TablesHeader")), constraints);

                constraints.gridy = 0;
                constraints.weightx = 1;
                constraints.weighty = 1;       
                constraints.fill = GridBagConstraints.BOTH;
                javaPanel.add(new JScrollPane(tableList), constraints);

//                constraints.gridx = 4;
//                constraints.weightx = 1;
//                constraints.weighty = 0;
//                constraints.gridwidth = GridBagConstraints.REMAINDER;
//                javaPanel.add(new JLabel(""), constraints);

                constraints.gridy = 1;
                constraints.weightx = 1;
                constraints.weighty = 0;       
                constraints.fill = GridBagConstraints.NONE;
                javaPanel.add(selectAllButton, constraints);

                return javaPanel;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#initControls()
             */
            @Override
            protected boolean initControls () {
                // If the connection has been changed since the tables were fetched, rebuild the list.
                DefaultListModel tableListModel = (DefaultListModel) tableList.getModel();
                if (!connectionForTables.equals(wizardState.connectionGemName)) {
                    tableListModel.removeAllElements();
                    wizardState.tables.clear();
                }

                // Populate the table list, if necessary.
                if (tableListModel.isEmpty()) {

                    // Add each available table.
                    List<String> tableNames = fetchTableNames();
                    for (final String tableName : tableNames) {
                        tableListModel.addElement(tableName)
                    }

                    connectionForTables = wizardState.connectionGemName;
                }

                // Update the controls with the current values.
                List<Integer> selectionIndexList = new ArrayList<Integer>();

                for (final String table : wizardState.tables) {
                    int listIndex = tableListModel.indexOf(table);
                    if (listIndex >= 0) {
                        selectionIndexList.add(Integer.valueOf(listIndex));
                    }
                }

                int[] selectionIndices = new int[selectionIndexList.size()];
                for (int indexN = 0, nIndices = selectionIndexList.size(); indexN < nIndices; ++indexN) {
                    int selectionIndex = selectionIndexList.get(indexN).intValue();
                    selectionIndices[indexN] = selectionIndex;
                }
                tableList.setSelectedIndices(selectionIndices);


                return true;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#commitChanges()
             */
            @Override
            protected boolean commitChanges () {
                wizardState.tables.clear();
                Object[] selectedValues = tableList.getSelectedValues();
                for (int valueN = 0, nValues = selectedValues.length; valueN < nValues; ++valueN) {
                    wizardState.tables.add((String)selectedValues[valueN]);
                }

                return true;
            }

            /**
             * @see org.openquark.util.ui.WizardCard#canFinish()
             */
            @Override
            protected boolean canFinish () {
                return (tableList.getSelectedValue() != null);
            }

            /**
             * @see org.openquark.util.ui.WizardCard#getTipInfo()
             */
            @Override
            protected TipInfo getTipInfo () {
                // Check whether any tables has been specified.
                if (tableList.getSelectedValue() == null) {
                    return new TipInfo (WARNING_TIP, GeneratorMessages.getString("DBTableGF_Tip_SelectTables"));
                }
                return new TipInfo (ALLOK_TIP, GeneratorMessages.getString("DBTableGF_Tip_FinishToGenerateGems"));
            }

            /**
             * @see org.openquark.util.ui.WizardCard#onFinish()
             */
            @Override
            protected boolean onFinish () {
                return commitChanges();
            }

            /**
             * Returns a list of the table names for the current connection.
             */
            private List <String> fetchTableNames() {
                // TODO: return qualified table names...
                String code = CAL_Prelude.Functions.output.getQualifiedName() + " (" + CAL_DataGems.Functions.jdbcGetConnectionTableNames.getQualifiedName() + " " + wizardState.connectionGemName + ")";
                return UnsafeCast.unsafeCast(getListFromCode(code));
            }
        }


        // TODO: other cards...

    }
}
TOP

Related Classes of org.openquark.gems.client.generators.DatabaseTableGemGenerator$DatabaseTableGemGeneratorDialog$DatabaseTableGemGeneratorCardStack

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.