/*
* 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.modelgenerator.xml.wizards;
import java.sql.DatabaseMetaData;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.NewFolderDialog;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.core.designer.util.FileUtils;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.metamodel.MetamodelDescriptor;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.jdbc.CaseConversion;
import org.teiid.designer.jdbc.JdbcImportSettings;
import org.teiid.designer.jdbc.JdbcPlugin;
import org.teiid.designer.jdbc.JdbcSource;
import org.teiid.designer.jdbc.metadata.JdbcDatabase;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.relational.RelationalPackage;
import org.teiid.designer.modelgenerator.xml.XMLExtensionsFilter;
import org.teiid.designer.modelgenerator.xml.jdbc.ui.util.JdbcUiUtil;
import org.teiid.designer.ui.UiConstants;
import org.teiid.designer.ui.common.InternalUiConstants;
import org.teiid.designer.ui.common.dialog.FolderSelectionDialog;
import org.teiid.designer.ui.common.util.UiUtil;
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.wizard.IPersistentWizardPage;
import org.teiid.designer.ui.explorer.ModelExplorerLabelProvider;
import org.teiid.designer.ui.viewsupport.ModelNameUtil;
import org.teiid.designer.ui.viewsupport.ModelProjectSelectionStatusValidator;
import org.teiid.designer.ui.viewsupport.ModelResourceSelectionValidator;
/**
* @since 4.0
*/
final class JdbcImportOptionsPage extends WizardPage implements
InternalUiConstants.Widgets,
IPersistentWizardPage,
UiConstants {
//============================================================================================================================
// Constants
private static final String I18N_PREFIX = I18nUtil.getPropertyPrefix(JdbcImportOptionsPage.class);
private static final String TITLE = getString("title"); //$NON-NLS-1$
private static final int COLUMN_COUNT = 3;
private static final String INITIAL_MESSAGE_ID = "initialMessage"; //$NON-NLS-1$
private static final String NO_NODEL_TO_UPDATE_MESSAGE_ID = "noModelToUpdateMessage"; //$NON-NLS-1$
private static final String NAME_LABEL = getString("nameLabel"); //$NON-NLS-1$
private static final String FOLDER_LABEL = getString("folderLabel"); //$NON-NLS-1$
private static final String UPDATE_CHECKBOX = getString("updateCheckBox"); //$NON-NLS-1$
private static final String MODEL_OBJECT_NAMES_GROUP = getString("modelObjectNamesGroup"); //$NON-NLS-1$
private static final String NONE_BUTTON = getString("noneButton"); //$NON-NLS-1$
private static final String UPPERCASE_BUTTON = getString("uppercaseButton"); //$NON-NLS-1$
private static final String LOWERCASE_BUTTON = getString("lowercaseButton"); //$NON-NLS-1$
private static final String MODEL_OBJECT_NAMES_DESCRIPTION = getString("modelObjectNamesDescription"); //$NON-NLS-1$
private static final String FILE_EXISTS_MESSAGE = getString("fileExistsMessage", UPDATE_CHECKBOX); //$NON-NLS-1$
private static final String NOT_MODEL_PROJECT_MESSAGE = getString("notModelProjectMessage"); //$NON-NLS-1$
private static final String NOT_RELATIONAL_MODEL_MESSAGE = getString("notRelationalModelMessage"); //$NON-NLS-1$
private static final String READ_ONLY_MODEL_MESSAGE = getString("readOnlyModelMessage"); //$NON-NLS-1$
private static final String VIRTUAL_MODEL_MESSAGE = getString("virtualModelMessage"); //$NON-NLS-1$
//============================================================================================================================
// Static Methods
/**
* @since 4.0
*/
private static String getString(final String id) {
return Util.getString(I18N_PREFIX + id);
}
/**
* @since 4.0
*/
private static String getString(final String id,
final Object parameter) {
return Util.getString(I18N_PREFIX + id, parameter);
}
//============================================================================================================================
// Variables
private JdbcDatabase db;
private JdbcImportSettings importSettings;
private Text nameText, folderText;
private Button updateCheckBox, schemaCheckBox, noneButton, uppercaseButton, lowercaseButton;
private boolean initd;
private IContainer folder;
//============================================================================================================================
// Constructors
/**
* @param pageName
* @since 4.0
*/
JdbcImportOptionsPage() {
super(JdbcImportOptionsPage.class.getSimpleName(), TITLE, null);
}
//============================================================================================================================
// Implemented Methods
/**
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
* @since 4.0
*/
@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);
CLabel label = new CLabel(pg, SWT.NONE);
label.setText(NAME_LABEL);
final GridData gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
gridData.horizontalSpan = 1;
label.setLayoutData(gridData);
this.nameText = WidgetFactory.createTextField(pg, GridData.FILL_HORIZONTAL);
this.nameText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(final ModifyEvent event) {
nameModified();
}
});
// add browse button to allow selecting a model in the workspaced to update
Button btn = WidgetFactory.createButton(pg, BROWSE_BUTTON);
btn.setToolTipText(getString("browseModelButton.tip")); //$NON-NLS-1$
btn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
browseModelSelected();
}
});
CLabel label2 = new CLabel(pg, SWT.NONE);
label2.setText(FOLDER_LABEL);
final GridData gridData2 = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
gridData2.horizontalSpan = 1;
label2.setLayoutData(gridData2);
final IContainer folder = ((XsdAsRelationalImportWizard)getWizard()).getFolder();
final String name = (folder == null ? null : folder.getFullPath().makeRelative().toString());
this.folderText = WidgetFactory.createTextField(pg, GridData.FILL_HORIZONTAL, name);
this.folderText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(final ModifyEvent event) {
folderModified();
}
});
WidgetFactory.createButton(pg, BROWSE_BUTTON).addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
browseButtonSelected();
}
});
this.updateCheckBox = WidgetFactory.createCheckBox(pg, UPDATE_CHECKBOX, 0, COLUMN_COUNT);
this.updateCheckBox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
updateCheckBoxSelected();
}
});
final Group modelObjNamesGroup = WidgetFactory.createGroup(pg,
MODEL_OBJECT_NAMES_GROUP,
GridData.HORIZONTAL_ALIGN_FILL,
COLUMN_COUNT);
{
CLabel label3 = new CLabel(modelObjNamesGroup, SWT.WRAP);
label3.setText(MODEL_OBJECT_NAMES_DESCRIPTION);
final GridData gridData3 = new GridData(GridData.FILL_HORIZONTAL);
gridData3.horizontalSpan = 1;
label3.setLayoutData(gridData3);
this.noneButton = WidgetFactory.createRadioButton(modelObjNamesGroup, NONE_BUTTON);
this.noneButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
noneButtonSelected();
}
});
this.uppercaseButton = WidgetFactory.createRadioButton(modelObjNamesGroup, UPPERCASE_BUTTON);
this.uppercaseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
uppercaseButtonSelected();
}
});
this.lowercaseButton = WidgetFactory.createRadioButton(modelObjNamesGroup, LOWERCASE_BUTTON);
this.lowercaseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
lowercaseButtonSelected();
}
});
}
}
/**
* @see org.teiid.designer.ui.common.wizard.IPersistentWizardPage#saveSettings()
* @since 4.0
*/
@Override
public void saveSettings() {
final IDialogSettings dlgSettings = getDialogSettings();
final XsdAsRelationalImportWizard wizard = (XsdAsRelationalImportWizard)getWizard();
// 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 JdbcImportSettings importSettings = wizard.getSource().getImportSettings();
try {
final DatabaseMetaData metadata = wizard.getDatabase().getDatabaseMetaData();
dlgSettings.put(metadata.getSchemaTerm(), importSettings.isCreateSchemasInModel());
} catch (final Exception err) {
Util.log(err);
WidgetUtil.showError(err);
}
dlgSettings.put(MODEL_OBJECT_NAMES_GROUP, importSettings.getConvertCaseInModel().getName());
}
public boolean updateSelected() {
if ( updateCheckBox != null ) {
return updateCheckBox.getSelection();
}
return false;
}
//============================================================================================================================
// Overridden Methods
/**
* @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean)
* @since 4.0
*/
@Override
public void setVisible(final boolean visible) {
if (visible) {
final XsdAsRelationalImportWizard wizard = (XsdAsRelationalImportWizard)getWizard();
this.db = wizard.getDatabase();
final String name = wizard.getModelName();
this.nameText.setText(name);
try {
// Save object selections from previous page
final JdbcSource src = wizard.getSource();
JdbcPlugin.recordJdbcDatabaseSelections(src, this.db);
// Initialize widgets
this.importSettings = src.getImportSettings();
if (!this.initd) {
this.initd = true;
final IDialogSettings dlgSettings = getDialogSettings();
final DatabaseMetaData metadata = this.db.getDatabaseMetaData();
final String catalogTerm = metadata.getCatalogTerm();
final String schemaTerm = metadata.getSchemaTerm();
if (!((XsdAsRelationalImportWizard)getWizard()).isUpdatedModel() && dlgSettings.get(catalogTerm) != null) {
this.importSettings.setCreateSchemasInModel(dlgSettings.getBoolean(schemaTerm));
this.importSettings.setConvertCaseInModel(CaseConversion.get(dlgSettings.get(MODEL_OBJECT_NAMES_GROUP)));
}
if(wizard.getStateManager().isUsingNoCatalog()) {
importSettings.setCreateCatalogsInModel(false);
} else {
importSettings.setCreateCatalogsInModel(true);
}
//This is here because this is where it used to happen
}
switch (this.importSettings.getConvertCaseInModel().getValue()) {
case CaseConversion.NONE:
{
this.noneButton.setSelection(true);
break;
}
case CaseConversion.TO_UPPERCASE:
{
this.uppercaseButton.setSelection(true);
break;
}
case CaseConversion.TO_LOWERCASE:
{
this.lowercaseButton.setSelection(true);
break;
}
}
} catch (final Exception err) {
JdbcUiUtil.showAccessError(err);
}
validatePage();
if (isPageComplete()) {
setMessage(getString(INITIAL_MESSAGE_ID, name));
}
}
super.setVisible(visible);
}
//============================================================================================================================
// MVC Controller Methods
void browseModelSelected() {
MetamodelDescriptor descriptor = ModelerCore.getMetamodelRegistry().getMetamodelDescriptor(RelationalPackage.eNS_URI);
Object[] resources = WidgetUtil.showWorkspaceObjectSelectionDialog(getString("dialog.modelChooser.title"), //$NON-NLS-1$
getString("dialog.modelChooser.msg"), //$NON-NLS-1$
false,
((XsdAsRelationalImportWizard)getWizard()).getFolder(),
new XMLExtensionsFilter(),
new ModelResourceSelectionValidator(descriptor, false),
new ModelExplorerLabelProvider());
if ((resources != null) && (resources.length > 0)) {
IFile model = (IFile)resources[0];
IContainer folder = model.getParent();
this.nameText.setText(model.getName());
this.folderText.setText((folder == null) ? "" //$NON-NLS-1$
: folder.getFullPath().makeRelative().toString());
this.updateCheckBox.setSelection(true);
updateCheckBoxSelected(); // to get handler activated
}
}
/**
* @since 4.0
*/
void browseButtonSelectedOLD() {
final ViewerFilter filter = new ViewerFilter() {
@Override
public boolean select(final Viewer viewer,
final Object parent,
final Object element) {
try {
return (((IContainer)element).getProject().getNature(ModelerCore.NATURE_ID) != null);
} catch (final CoreException err) {
Util.log(err);
return false;
}
}
};
final IContainer folder = WidgetUtil.showFolderSelectionDialog(((XsdAsRelationalImportWizard)getWizard()).getFolder(),
filter,
new ModelProjectSelectionStatusValidator());
if (folder != null) {
this.folderText.setText(folder.getFullPath().makeRelative().toString());
validatePage();
}
}
/**
* @since 4.0
*/
void browseButtonSelected() {
IContainer folder = getFolder();
if (folder != null) {
this.folderText.setText(folder.getFullPath().makeRelative().toString());
validatePage();
}
}
private IContainer getFolder() {
// create the filter
final ViewerFilter filter = getFilter();
// create the dialog
FolderSelectionDialog dlg = new FolderSelectionDialog( Display.getCurrent().getActiveShell(),
new WorkbenchLabelProvider(),
new WorkbenchContentProvider() );
dlg.setInitialSelection( ((XsdAsRelationalImportWizard)getWizard()).getFolder() );
dlg.addFilter( filter );
dlg.setValidator( new ModelProjectSelectionStatusValidator() );
dlg.setAllowMultiple( false );
dlg.setInput( ModelerCore.getWorkspace().getRoot() );
// display the dialog
Object[] objs = new Object[ 1 ];
if ( dlg.open() == Window.OK ) {
objs = dlg.getResult();
}
return ( objs.length == 0 ? null : (IContainer)objs[0] );
}
private ViewerFilter getFilter() {
// create the filter
final ViewerFilter filter = new ViewerFilter() {
@Override
public boolean select(final Viewer viewer,
final Object parent,
final Object element) {
boolean result = false;
if (element instanceof IResource) {
// If the project is closed, dont show
boolean projectOpen = ((IResource)element).getProject().isOpen();
if(projectOpen) {
// Show projects
if(element instanceof IProject) {
result = true;
// Show folders
} else if (element instanceof IFolder ) {
result = true;
}
}
}
return result;
}
};
return filter;
}
/**
* @since 4.0
*/
void folderModified() {
validatePage();
}
/**
* @since 4.0
*/
void lowercaseButtonSelected() {
if (this.lowercaseButton.getSelection()) {
this.importSettings.setConvertCaseInModel(CaseConversion.TO_LOWERCASE_LITERAL);
}
}
/**
* @since 4.0
*/
void nameModified() {
validatePage();
}
/**
* @since 4.0
*/
protected void newFolderButtonSelected(final TreeViewer viewer,
final IContainer folder) {
final NewFolderDialog dlg = new NewFolderDialog(getShell(), folder);
if (dlg.open() == Window.OK) {
viewer.refresh(folder);
final Object newFolder = dlg.getResult()[0];
viewer.setSelection(new StructuredSelection(newFolder), true);
}
}
/**
* @since 4.0
*/
void noneButtonSelected() {
if (this.noneButton.getSelection()) {
this.importSettings.setConvertCaseInModel(CaseConversion.NONE_LITERAL);
}
}
/**
* @since 4.0
*/
void schemaCheckBoxSelected() {
this.importSettings.setCreateSchemasInModel(this.schemaCheckBox.getSelection());
}
/**
* @since 4.0
*/
void updateCheckBoxSelected() {
/*
* jhTODO: when checkbox is true, disable finish, enable next
*/
if (this.updateCheckBox.getSelection()) {
final IStructuredSelection selection = UiUtil.getStructuredSelection();
if (selection.size() == 1) {
final ModelResource model;
try {
model = ModelUtil.getModel(selection.getFirstElement());
if (model != null && !model.isReadOnly()) {
if (model.getModelType().getValue() != ModelType.VIRTUAL) {
this.nameText.setText(model.getItemName());
// Return here (skipping call to validatePage) since previous line that sets the model name will end
// up calling validatePage anyway.
return;
}
}
} catch (final ModelWorkspaceException err) {
Util.log(err);
WidgetUtil.showError(err.getLocalizedMessage());
}
}
}
validatePage();
}
/**
* @since 4.0
*/
void uppercaseButtonSelected() {
if (this.uppercaseButton.getSelection()) {
this.importSettings.setConvertCaseInModel(CaseConversion.TO_UPPERCASE_LITERAL);
}
}
//============================================================================================================================
// Utility Methods
/**
* @since 4.0
*/
private void validatePage() {
final boolean updating = this.updateCheckBox.getSelection();
try {
// making 'folder' an instance var so that canFlipToNextPage() can use it w/o recreating it
folder = WizardUtil.validateFileAndFolder(this.nameText,
this.folderText,
this,
ModelerCore.MODEL_FILE_EXTENSION,
updating ? NONE : ERROR);
// Check if folder's project is a model project
if (folder != null && folder.getProject().getNature(ModelerCore.NATURE_ID) == null) {
WizardUtil.setPageComplete(this, NOT_MODEL_PROJECT_MESSAGE, ERROR);
folder = null;
}
// Check if model name is valid
String name = this.nameText.getText();
IStatus status = ModelNameUtil.validate(name, ModelerCore.MODEL_FILE_EXTENSION, folder,
ModelNameUtil.IGNORE_CASE | ModelNameUtil.NO_DUPLICATE_MODEL_NAMES);
if( status.getSeverity() == IStatus.ERROR ) {
WizardUtil.setPageComplete(this, ModelNameUtil.MESSAGES.INVALID_MODEL_NAME + status.getMessage(), ERROR);
folder = null;
}
if (isPageComplete()) {
name = FileUtils.toFileNameWithExtension(name, ModelerCore.MODEL_FILE_EXTENSION);
final IFile file = folder.getFile(new Path(name));
if (file.exists()) {
try {
final ModelResource model = ModelerCore.getModelEditor().findModelResource(file);
if (model.isReadOnly()) {
WizardUtil.setPageComplete(this, READ_ONLY_MODEL_MESSAGE, ERROR);
return;
}
if (!RelationalPackage.eNS_URI.equals(model.getPrimaryMetamodelDescriptor().getNamespaceURI())) {
WizardUtil.setPageComplete(this, NOT_RELATIONAL_MODEL_MESSAGE, ERROR);
return;
}
if (model.getModelType().getValue() == ModelType.VIRTUAL) {
WizardUtil.setPageComplete(this, VIRTUAL_MODEL_MESSAGE, ERROR);
return;
}
} catch (final ModelWorkspaceException err) {
Util.log(err);
WidgetUtil.showError(err.getLocalizedMessage());
}
} else if (updating) {
WizardUtil.setPageComplete(this,
getString(NO_NODEL_TO_UPDATE_MESSAGE_ID, file.getFullPath().makeRelative()),
ERROR);
return;
}
final XsdAsRelationalImportWizard wizard = (XsdAsRelationalImportWizard)getWizard();
wizard.setModelName(name);
wizard.setFolder(folder);
getContainer().updateButtons();
} else if (folder != null) {
WizardUtil.setPageComplete(this, getMessage() + '\n' + FILE_EXISTS_MESSAGE, getMessageType());
}
} catch (final CoreException err) {
Util.log(err);
WizardUtil.setPageComplete(this, err.getLocalizedMessage(), ERROR);
}
}
@Override
public boolean canFlipToNextPage() {
/*
* I have added a new, final page to this wizard that follows this
* page and shows the DifferenceReport in the case in which the
* user is using this wizard to update a previously created model from
* the JDBC imported metadata. In the non-update case it is important
* that this page NOT enable the Next button. I am overriding this
* WizardPage method to accomplish that.
*
* return ( updating && isPageComplete() && folder != null && fileExists )? true : false;
*/
final boolean updating = this.updateCheckBox.getSelection();
IFile file = null;
if ( folder != null ) {
String name = this.nameText.getText();
name = FileUtils.toFileNameWithExtension(name, ModelerCore.MODEL_FILE_EXTENSION);
file = folder.getFile(new Path(name));
}
return ( folder != null && file != null && updating && isPageComplete() && file.exists() );
}
}