/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.jdbc.ui.wizards; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.teiid.core.designer.util.I18nUtil; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.jdbc.JdbcImportSettings; import org.teiid.designer.jdbc.JdbcSource; import org.teiid.designer.jdbc.metadata.Includes; import org.teiid.designer.jdbc.metadata.JdbcDatabase; import org.teiid.designer.jdbc.relational.JdbcImporter; import org.teiid.designer.jdbc.ui.util.JdbcUiUtil; import org.teiid.designer.ui.UiConstants; import org.teiid.designer.ui.common.InternalUiConstants; import org.teiid.designer.ui.common.util.WidgetFactory; import org.teiid.designer.ui.common.util.WidgetUtil; import org.teiid.designer.ui.common.util.WizardUtil; import org.teiid.designer.ui.common.widget.DefaultScrolledComposite; import org.teiid.designer.ui.common.widget.IListPanelController; import org.teiid.designer.ui.common.widget.ListPanel; import org.teiid.designer.ui.common.widget.ListPanelAdapter; import org.teiid.designer.ui.common.wizard.IPersistentWizardPage; /** * @since 4.0 */ final class JdbcImportMetadataPage extends WizardPage implements InternalUiConstants.Widgets, IPersistentWizardPage, ListPanel.Constants, UiConstants { //============================================================================================================================ // Constants private static final String I18N_PREFIX = I18nUtil.getPropertyPrefix(JdbcImportMetadataPage.class); private static final String TITLE = getString("title"); //$NON-NLS-1$ private static final String TITLE_WITH_VDB_SOURCE = TITLE + " (VDB source model)"; //$NON-NLS-1$ private static final String APPROXIMATIONS_BUTTON = getString("approximationsButton"); //$NON-NLS-1$ private static final String FOREIGN_KEYS_BUTTON = getString("foreignKeysButton"); //$NON-NLS-1$ private static final String INCOMPLETE_FK_BUTTON = getString("incompleteFKButton"); //$NON-NLS-1$ private static final String INDEXES_BUTTON = getString("indexesButton"); //$NON-NLS-1$ private static final String PROCEDURES_BUTTON = getString("proceduresButton"); //$NON-NLS-1$ private static final String UNIQUE_BUTTON = getString("uniqueButton"); //$NON-NLS-1$ private static final String TABLE_TYPES_GROUP = getString("tableTypesGroup"); //$NON-NLS-1$ private static final String INITIAL_MESSAGE = getString("initialMessage"); //$NON-NLS-1$ private static final String INVALID_PAGE_MESSAGE = getString("invalidPageMessage", PROCEDURES_BUTTON, TABLE_TYPES_GROUP); //$NON-NLS-1$ private static final int COLUMN_COUNT = 2; private static final int CHECKBOX_TEXT_GAP = 5; //============================================================================================================================ // Static Methods /**<p> * </p> * @since 4.0 */ private static String getString(final String id) { return Util.getString(I18N_PREFIX + id); } /**<p> * </p> * @since 4.0 */ private static String getString(final String id, final String parameter1, final String parameter2) { return Util.getString(I18N_PREFIX + id, parameter1, parameter2); } //============================================================================================================================ // Variables private Includes incls; private JdbcImportSettings importSettings; private Button foreignKeysCheckBox, incompleteFKCheckBox, indexesCheckBox, uniqueCheckBox, approximationsCheckBox, proceduresCheckBox; private ListPanel listPanel; private Map enableMap; private boolean initd; private JdbcImporter importer; //============================================================================================================================ // Constructors /**<p> * </p> * @param pageName * @since 4.0 */ JdbcImportMetadataPage() { super(JdbcImportMetadataPage.class.getSimpleName(), TITLE, null); } //============================================================================================================================ // Implemented Methods /**<p> * </p> * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) * @since 4.0 */ @SuppressWarnings("unused") @Override public void createControl(final Composite parent) { // // Create page // final Composite pg = new Composite(parent, SWT.NONE); // pg.setLayout(new GridLayout(COLUMN_COUNT, false)); // setControl(pg); final Composite hostPanel = new Composite(parent, SWT.NONE); hostPanel.setLayout(new GridLayout(1, false)); hostPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // Create page DefaultScrolledComposite scrolledComposite = new DefaultScrolledComposite(hostPanel, SWT.H_SCROLL | SWT.V_SCROLL); scrolledComposite.setExpandHorizontal(true); scrolledComposite.setExpandVertical(true); GridLayoutFactory.fillDefaults().equalWidth(false).applyTo(scrolledComposite); GridDataFactory.fillDefaults().grab(true, false); final Composite mainPanel = scrolledComposite.getPanel(); //new Composite(scrolledComposite, SWT.NONE); mainPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mainPanel.setLayout(new GridLayout(2, false)); ((GridData)mainPanel.getLayoutData()).minimumWidth = 400; // Add widgets to page final Composite checkBoxPanel = WidgetFactory.createPanel(mainPanel, SWT.NO_TRIM, GridData.VERTICAL_ALIGN_BEGINNING); { this.foreignKeysCheckBox = WidgetFactory.createCheckBox(checkBoxPanel); this.foreignKeysCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent event) { foreignKeysCheckBoxSelected(); } }); final int fkIndent = this.foreignKeysCheckBox.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x + CHECKBOX_TEXT_GAP; this.foreignKeysCheckBox.setText(FOREIGN_KEYS_BUTTON); this.incompleteFKCheckBox = createNestedCheckbox(checkBoxPanel, INCOMPLETE_FK_BUTTON, fkIndent); this.incompleteFKCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected( final SelectionEvent event ) { incompleteFKsCheckBoxSelected(); } }); this.indexesCheckBox = WidgetFactory.createCheckBox(checkBoxPanel); this.indexesCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent event) { indexesCheckBoxSelected(); } }); final int indent = this.indexesCheckBox.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x + CHECKBOX_TEXT_GAP; this.indexesCheckBox.setText(INDEXES_BUTTON); this.uniqueCheckBox = createNestedCheckbox(checkBoxPanel, UNIQUE_BUTTON, indent); this.uniqueCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent event) { uniqueCheckBoxSelected(); } }); this.approximationsCheckBox = createNestedCheckbox(checkBoxPanel, APPROXIMATIONS_BUTTON, indent); this.approximationsCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent event) { approximationsCheckBoxSelected(); } }); this.proceduresCheckBox = WidgetFactory.createCheckBox(checkBoxPanel, PROCEDURES_BUTTON); this.proceduresCheckBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent event) { procuduresButtonSelected(); } }); } final IListPanelController ctrlr = new ListPanelAdapter() { @Override public Object[] addButtonSelected() { return null; } }; this.listPanel = new ListPanel(mainPanel, TABLE_TYPES_GROUP, ctrlr, SWT.READ_ONLY | SWT.MULTI, ITEMS_COMMONLY_ALL_SELECTED); ((GridData)listPanel.getLayoutData()).minimumHeight = 240; this.listPanel.getViewer().addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(final SelectionChangedEvent event) { tableTypesSelected(event); } }); scrolledComposite.sizeScrolledPanel(); setControl(hostPanel); } /**<p> * </p> * @see org.teiid.designer.ui.common.wizard.IPersistentWizardPage#saveSettings() * @since 4.0 */ @Override public void saveSettings() { final IDialogSettings dlgSettings = getDialogSettings(); // Information must be obtained from wizard, not local variables, since this method may be called w/o this page every // being set visible, via the user having pre-selected a destination folder and clicking on the "Finish" earlier in the // wizard. final Includes incls = ((JdbcImportWizard)getWizard()).getDatabase().getIncludes(); dlgSettings.put(APPROXIMATIONS_BUTTON, incls.getApproximateIndexes()); dlgSettings.put(FOREIGN_KEYS_BUTTON, incls.includeForeignKeys()); dlgSettings.put(INCOMPLETE_FK_BUTTON, incls.includeIncompleteFKs()); dlgSettings.put(INDEXES_BUTTON, incls.includeIndexes()); dlgSettings.put(PROCEDURES_BUTTON, incls.includeProcedures()); dlgSettings.put(UNIQUE_BUTTON, incls.getUniqueIndexesOnly()); final String[] tableTypes = incls.getIncludedTableTypes(); if (tableTypes != null) { dlgSettings.put(TABLE_TYPES_GROUP, tableTypes); } } //============================================================================================================================ // Overridden Methods /**<p> * </p> * @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean) * @since 4.0 */ @Override public void setVisible(final boolean visible) { if (visible) { // Wrap in transaction so it doesn't result in Significant Undoable boolean started = ModelerCore.startTxn(false, false, "Initializing Import Settings", this); //$NON-NLS-1$ boolean succeeded = false; try { initializeInTransaction(); succeeded = true; } finally { if ( started ) { if ( succeeded ) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } setMessage(INITIAL_MESSAGE); if( this.importer.isVdbSourceModel() ) { this.setTitle(TITLE_WITH_VDB_SOURCE); } else { this.setTitle(TITLE); } super.setVisible(visible); } void initializeInTransaction() { if( this.importer.isReachedObjectsPage()) { final List lastTypes = this.importSettings.getIncludedTableTypes(); if (lastTypes != null && !lastTypes.isEmpty()) { this.listPanel.getTableViewer().setSelection(new StructuredSelection(lastTypes)); } return; } // Connect to database chosen in previous page final JdbcDatabase db = ((JdbcImportWizard)getWizard()).getDatabase(); if (db == null) { return; } // Get database's includes this.incls = db.getIncludes(); final JdbcSource src = ((JdbcImportWizard)getWizard()).getSource(); this.importSettings = src.getImportSettings(); // Initialize widgets with inclusion information final IDialogSettings dlgSettings = getDialogSettings(); final boolean updating = ((JdbcImportWizard)getWizard()).isUpdatedModel(); if (!updating && dlgSettings.get(PROCEDURES_BUTTON) != null && !this.initd) { this.initd = true; this.incls.setApproximateIndexes(dlgSettings.getBoolean(APPROXIMATIONS_BUTTON)); this.incls.setIncludeForeignKeys(dlgSettings.getBoolean(FOREIGN_KEYS_BUTTON)); this.incls.setIncludeIncompleteFKs(dlgSettings.getBoolean(INCOMPLETE_FK_BUTTON)); this.incls.setIncludeIndexes(dlgSettings.getBoolean(INDEXES_BUTTON)); this.incls.setIncludeProcedures(dlgSettings.getBoolean(PROCEDURES_BUTTON)); this.incls.setUniqueIndexesOnly(dlgSettings.getBoolean(UNIQUE_BUTTON)); this.incls.setIncludedTableTypes(dlgSettings.getArray(TABLE_TYPES_GROUP)); this.importSettings.setIncludeApproximateIndexes(dlgSettings.getBoolean(APPROXIMATIONS_BUTTON)); this.importSettings.setIncludeForeignKeys(dlgSettings.getBoolean(FOREIGN_KEYS_BUTTON)); this.importSettings.setIncludeIndexes(dlgSettings.getBoolean(INDEXES_BUTTON)); this.importSettings.setIncludeProcedures(dlgSettings.getBoolean(PROCEDURES_BUTTON)); this.importSettings.setIncludeUniqueIndexes(dlgSettings.getBoolean(UNIQUE_BUTTON)); final List tableTypes = this.importSettings.getIncludedTableTypes(); final String[] ttypes = this.incls.getIncludedTableTypes(); for (int i = 0; i < ttypes.length; ++i) { final String tableType = ttypes[i]; tableTypes.add(tableType); } } else { this.incls.setApproximateIndexes(false); this.incls.setIncludeForeignKeys(true); this.incls.setIncludeIncompleteFKs(true); this.incls.setIncludeIndexes(false); this.incls.setIncludeProcedures(false); this.incls.setUniqueIndexesOnly(false); this.importSettings.setIncludeApproximateIndexes(true); this.importSettings.setIncludeForeignKeys(true); this.importSettings.setIncludeIndexes(false); this.importSettings.setIncludeProcedures(false); this.importSettings.setIncludeUniqueIndexes(false); } setSelected(this.approximationsCheckBox, this.incls.getApproximateIndexes()); setSelected(this.foreignKeysCheckBox, this.incls.includeForeignKeys()); setSelected(this.indexesCheckBox, this.incls.includeIndexes()); setSelected(this.proceduresCheckBox, this.incls.includeProcedures()); setSelected(this.uniqueCheckBox, this.incls.getUniqueIndexesOnly()); final TableViewer viewer = this.listPanel.getTableViewer(); for (Object obj = viewer.getElementAt(0); obj != null; obj = viewer.getElementAt(0)) { viewer.remove(obj); } ResultSet result = null; try { result = db.getDatabaseMetaData().getTableTypes(); final List types = new ArrayList(); while (result.next()) { String type = result.getString(1).trim(); if(!types.contains(type)) { types.add(type); } } // If this is an update, retain only the table types imported last time if (!types.isEmpty()) { viewer.add(types.toArray()); final List lastTypes = this.importSettings.getIncludedTableTypes(); if (lastTypes != null && !lastTypes.isEmpty()) { viewer.setSelection(new StructuredSelection(lastTypes)); } else { viewer.setSelection(new StructuredSelection(types)); } } } catch (final Exception err) { JdbcUiUtil.showAccessError(err); } finally { if ( result != null ) { try { result.close(); } catch (SQLException e) { UiConstants.Util.log(e); } } } } //============================================================================================================================ // MVC Controller Methods /**<p> * </p> * @param event * @since 4.0 */ void approximationsCheckBoxSelected() { boolean requiredStart = ModelerCore.startTxn(false,false,"Set Opproxomations Option",this); //$NON-NLS-1$ boolean succeeded = false; try { this.incls.setApproximateIndexes(this.approximationsCheckBox.getSelection()); this.importSettings.setIncludeApproximateIndexes(this.incls.getApproximateIndexes()); succeeded = true; } finally { // If we start txn, commit it if(requiredStart) { if(succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } /**<p> * </p> * @since 4.0 */ void foreignKeysCheckBoxSelected() { boolean requiredStart = ModelerCore.startTxn(false,false,"Set Foreign Keys Option",this); //$NON-NLS-1$ boolean succeeded = false; try { final boolean enabled = this.foreignKeysCheckBox.getSelection(); // Include incomplete selection stays in sync with Foreign keys selection this.incompleteFKCheckBox.setSelection(enabled); this.incompleteFKCheckBox.setEnabled(enabled); this.incls.setIncludeForeignKeys(this.foreignKeysCheckBox.getSelection()); this.incls.setIncludeIncompleteFKs(this.incompleteFKCheckBox.getSelection()); this.importSettings.setIncludeForeignKeys(this.incls.includeForeignKeys()); succeeded = true; } finally { // If we start txn, commit it if(requiredStart) { if(succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } /** * <p> * </p> * * @param event * @since 4.0 */ void incompleteFKsCheckBoxSelected() { boolean requiredStart = ModelerCore.startTxn(false, false, "Set Include Incomplete FKs Option", this); //$NON-NLS-1$ boolean succeeded = false; try { this.incls.setIncludeIncompleteFKs(this.incompleteFKCheckBox.getSelection()); succeeded = true; } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } /**<p> * </p> * @since 4.0 */ void indexesCheckBoxSelected() { boolean requiredStart = ModelerCore.startTxn(false,false,"Set Indexes Option",this); //$NON-NLS-1$ boolean succeeded = false; try { final boolean enabled = this.indexesCheckBox.getSelection(); // Keep approximations check box in sync when indexes are checked. This will improve import performance // for the default case. users can uncheck approx. check box if they wish. this.approximationsCheckBox.setSelection(enabled); this.approximationsCheckBox.setEnabled(enabled); this.incls.setIncludeIndexes(enabled); this.incls.setApproximateIndexes(enabled); this.uniqueCheckBox.setEnabled(enabled); this.importSettings.setIncludeIndexes(this.incls.includeIndexes()); this.importSettings.setIncludeUniqueIndexes(this.incls.getUniqueIndexesOnly()); this.importSettings.setIncludeApproximateIndexes(this.incls.getApproximateIndexes()); succeeded = true; } finally { // If we start txn, commit it if(requiredStart) { if(succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } /**<p> * </p> * @param event * @since 4.0 */ void procuduresButtonSelected() { boolean requiredStart = ModelerCore.startTxn(false,false,"Set Procedures Option",this); //$NON-NLS-1$ boolean succeeded = false; try { this.incls.setIncludeProcedures(this.proceduresCheckBox.getSelection()); this.importSettings.setIncludeProcedures(this.incls.includeProcedures()); succeeded = true; } finally { // If we start txn, commit it if(requiredStart) { if(succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } validatePage(); } /**<p> * </p> * @since 4.0 */ void tableTypesSelected(final SelectionChangedEvent event) { final IStructuredSelection selection = (IStructuredSelection)event.getSelection(); final String[] types = new String[selection.size()]; final List tableTypes = this.importSettings.getIncludedTableTypes(); tableTypes.clear(); final Iterator iter = selection.iterator(); for (int ndx = 0; ndx < types.length; ++ndx) { types[ndx] = (String)iter.next(); tableTypes.add(types[ndx]); } this.incls.setIncludedTableTypes(types); final boolean enabled = (types.length > 0); this.foreignKeysCheckBox.setEnabled(enabled); this.indexesCheckBox.setEnabled(enabled); if (enabled) { if (this.enableMap != null) { WidgetUtil.restore(this.enableMap); this.enableMap = null; } } else { this.enableMap = WidgetUtil.disable(new Control[] {this.uniqueCheckBox, this.approximationsCheckBox}); } validatePage(); } /**<p> * </p> * @param event * @since 4.0 */ void uniqueCheckBoxSelected() { boolean requiredStart = ModelerCore.startTxn(false,false,"Set Unique Indexes Option",this); //$NON-NLS-1$ boolean succeeded = false; try { this.incls.setUniqueIndexesOnly(this.uniqueCheckBox.getSelection()); this.importSettings.setIncludeUniqueIndexes(this.incls.getUniqueIndexesOnly()); succeeded = true; } finally { // If we start txn, commit it if(requiredStart) { if(succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } /** * @param importer the importer to set */ public void setImporter(JdbcImporter importer) { this.importer = importer; } //============================================================================================================================ // Utility Methods /**<p> * </p> * @since 4.0 */ private Button createNestedCheckbox(final Composite parent, final String text, final int indent) { final Button button = WidgetFactory.createCheckBox(parent, text); final GridData gridData = (GridData)button.getLayoutData(); gridData.horizontalIndent = indent; return button; } /**<p> * </p> * @since 4.0 */ private void setSelected(final Button checkBox, final boolean selected) { checkBox.setSelection(selected); checkBox.notifyListeners(SWT.Selection, new Event()); } /**<p> * </p> * @since 4.0 */ private void validatePage() { if (this.proceduresCheckBox.getSelection() || !this.listPanel.getViewer().getSelection().isEmpty()) { WizardUtil.setPageComplete(this); } else { WizardUtil.setPageComplete(this, INVALID_PAGE_MESSAGE, ERROR); } } }