/* * 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... } }