/*
* 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.ui.viewsupport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
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.graphics.Image;
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.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.ui.dialogs.ListDialog;
import org.eclipse.xsd.XSDSimpleTypeDefinition;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.types.DatatypeManager;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.ui.UiConstants;
import org.teiid.designer.ui.common.eventsupport.SelectionUtilities;
import org.teiid.designer.ui.common.util.WidgetFactory;
import org.teiid.designer.ui.filter.StructuredViewerDatatypeFilterer;
import org.teiid.designer.ui.filter.StructuredViewerFilterer;
import org.teiid.designer.ui.filter.StructuredViewerTextFilterer;
/**
* DatatypeSelectionDialog
*
* @since 8.0
*/
public class DatatypeSelectionDialog extends ListDialog implements UiConstants {
/** The logging prefix. */
private static final String PREFIX = "DatatypeSelectionDialog."; //$NON-NLS-1$
private static final String STRING_STRING = "string"; //$NON-NLS-1$
private static final String ONE_SPACE = " "; //$NON-NLS-1$
private static final String BUILT_IN = getString("builtInLabel"); //$NON-NLS-1$
private static final String PATH_GROUP_TITLE = getString("pathGroupLabel"); //$NON-NLS-1$
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static String getString( final String key ) {
return UiConstants.Util.getString(PREFIX + key);
}
private static String getString( final String key,
final Object obj ) {
return UiConstants.Util.getString(PREFIX + key, obj);
}
private Spinner ispin = null;
private int MIN = 0;
private int MAX = 99999;
private boolean editLength = false;
boolean setLengthForAll = false;
private boolean multipleObjects = false;
private int initialLength = 0;
private int currentLength = initialLength;
Button setLengthForAllCheckBox;
CLabel pathLabel;
private StructuredViewerDatatypeFilterer entFilter;
private String originalMessage;
/**
* Construct an instance of DatatypeSelectionDialog.
*
* @param parent the Shell for this dialog
*/
public DatatypeSelectionDialog( final Shell parent ) {
this(parent, null);
}
/**
* Construct an instance of DatatypeSelectionDialog.
*
* @param parent the Shell for this dialog
* @param objectForType an EObject that should be displayed in the message for setting the type on or <code>null</code>
*/
public DatatypeSelectionDialog( final Shell parent,
final EObject objectForType ) {
super(parent);
setContentProvider(new IStructuredContentProvider() {
@Override
public Object[] getElements( Object inputElement ) {
Object[] result = new Object[0];
try {
// Use the Datatype Manager that corresponds to the container where 'objectForType' exists
DatatypeManager dtmgr = ModelerCore.getDatatypeManager(objectForType, true);
// Get the list of all datatypes
List tmp = new ArrayList(Arrays.asList(dtmgr.getAllDatatypes()));
// Remove xs:anySimpleType or xs:anyType from the list
removeUrTypesFromList(tmp, dtmgr);
result = tmp.toArray();
} catch (ModelerCoreException e) {
Util.log(e);
}
return result;
}
@Override
public void dispose() {
}
@Override
public void inputChanged( Viewer v,
Object o,
Object o2 ) {
}
});
setLabelProvider(ModelUtilities.getEMFLabelProvider());
setAddCancelButton(true);
setTitle(getString("selectDatatypeTitle")); //$NON-NLS-1$
String msg = (objectForType == null) ? getString("selectDatatypeMessageNoObject") //$NON-NLS-1$
: getString("selectDatatypeMessage", //$NON-NLS-1$
objectForType.eClass().getName());
setMessage(msg);
setInput(Collections.EMPTY_LIST);
initFilter();
}
/**
* Construct an instance of DatatypeSelectionDialog.
*
* @param parent the Shell for this dialog
* @param objectForType an EObject that should be displayed in the message for setting the type on.
* @param feature the EStructuralFeature representing the type
*/
public DatatypeSelectionDialog( final Shell parent,
final EObject objectForType,
final EStructuralFeature feature ) {
super(parent);
setContentProvider(new IStructuredContentProvider() {
@Override
public Object[] getElements( Object inputElement ) {
Object[] result = new Object[0];
try {
// Use the Datatype Manager that corresponds to the container where 'objectForType' exists
DatatypeManager dtmgr = ModelerCore.getDatatypeManager(objectForType, true);
// Get the list of all datatypes
List tmp = new ArrayList(Arrays.asList(dtmgr.getAllowableTypeValues(objectForType, feature)));
// Remove xs:anySimpleType or xs:anyType from the list
removeUrTypesFromList(tmp, dtmgr);
result = tmp.toArray();
} catch (ModelerCoreException e) {
UiConstants.Util.log(e);
}
return result;
}
@Override
public void dispose() {
}
@Override
public void inputChanged( Viewer v,
Object o,
Object o2 ) {
}
});
setLabelProvider(ModelUtilities.getEMFLabelProvider());
setAddCancelButton(true);
setTitle(getString("selectDatatypeTitle")); //$NON-NLS-1$
setMessage(getString("selectDatatypeMessage", (objectForType).eClass().getName())); //$NON-NLS-1$
setInput(Collections.EMPTY_LIST);
initFilter();
}
/**
* Return a new list of datatypes with the ur-types (xs:anySimpleType, xs:anyType) removed
*
* @return
* @since 4.3
*/
void removeUrTypesFromList( final List types,
final DatatypeManager dtmgr ) {
try {
// Remove xs:anySimpleType or xs:anyType from the list
// remove "integer" type
for (Iterator i = types.iterator(); i.hasNext();) {
EObject eObj = (EObject)i.next();
if (dtmgr.getAnySimpleType() == eObj || dtmgr.getAnyType() == eObj) {
i.remove();
} else {
String name = ModelerCore.getModelEditor().getName(eObj);
if( name.equalsIgnoreCase("integer") ) {
i.remove();
}
}
}
} catch (ModelerCoreException e) {
UiConstants.Util.log(e);
}
}
/**
* Construct an instance of DatatypeSelectionDialog. A runtimeTypeName is also supplied - it is used to narrow the selection
* datatypes available in the dialog. Only the datatypes which are compatible with the supplied runtimetype will be shown.
*
* @param parent the Shell for this dialog
* @param objectForType an EObject that should be displayed in the message for setting the type on.
* @param runtimeTypeName the runtimeTypeName used to narrow the selections
*/
public DatatypeSelectionDialog( final Shell parent,
final EObject objectForType,
final String runtimeTypeName ) {
super(parent);
// modTODO: use the runtime typeName to narrow down the datatypes
setContentProvider(new IStructuredContentProvider() {
@Override
public Object[] getElements( Object inputElement ) {
Object[] result = new Object[0];
try {
// Use the Datatype Manager that corresponds to the container where 'objectForType' exists
DatatypeManager dtmgr = ModelerCore.getDatatypeManager(objectForType, true);
// Get the list of all datatypes
List tmp = new ArrayList(Arrays.asList(dtmgr.getAllDatatypes()));
// Remove xs:anySimpleType or xs:anyType from the list
removeUrTypesFromList(tmp, dtmgr);
result = tmp.toArray();
} catch (ModelerCoreException e) {
UiConstants.Util.log(e);
}
return result;
}
@Override
public void dispose() {
}
@Override
public void inputChanged( Viewer v,
Object o,
Object o2 ) {
}
});
setLabelProvider(ModelUtilities.getEMFLabelProvider());
setAddCancelButton(true);
setTitle(getString("selectDatatypeTitle")); //$NON-NLS-1$
setMessage(getString("selectDatatypeMessage", (objectForType).eClass().getName())); //$NON-NLS-1$
setInput(Collections.EMPTY_LIST);
initFilter();
}
//
// Methods:
//
private void initFilter() {
entFilter = new StructuredViewerDatatypeFilterer();
entFilter.setDelayTime(100);
setAllowSimple(false); // default to false, since most things don't need simple types.
}
public void setAllowSimple( boolean allow ) {
entFilter.setAllowSimple(allow);
if (!allow) {
// notify the user that some stuff is filtered:
originalMessage = getMessage();
setMessage(originalMessage + getString("simpleHiddenMessage")); //$NON-NLS-1$
} else {
if (originalMessage != null) {
setMessage(originalMessage);
} // endif
} // endif
}
/**
* @see org.eclipse.jface.window.Window#create()
* @since 4.2
*/
@Override
public void create() {
setShellStyle(getShellStyle() | SWT.RESIZE);
super.create();
// set OK button enable state to false if nothing selected
if (getInitialElementSelections().isEmpty()) {
getOkButton().setEnabled(false);
}
// setup selection listening in order to enable OK button when selection occurs
getTableViewer().addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged( SelectionChangedEvent theEvent ) {
getOkButton().setEnabled(!getTableViewer().getSelection().isEmpty());
updateSpinner(getTableViewer().getSelection());
// set path label text
EObject eObj = SelectionUtilities.getSelectedEObject(theEvent.getSelection());
pathLabel.setText((eObj == null) ? EMPTY_STRING : constructPath(eObj));
}
});
updateSpinner(getTableViewer().getSelection());
}
/**
* This implemenation does nothing, on purpose, to allow us to change the order of construction of the GUI. Yes, slightly
* evil. See createDialogArea for how this works.
*/
@Override
protected Label createMessageArea( Composite composite ) {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.window.Window#createContents(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createDialogArea( Composite parent ) {
//
if (multipleObjects) {
setLengthForAll = false;
} else {
setLengthForAll = true;
}
Composite composite = new Composite(parent, 0);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 5;
layout.verticalSpacing = 0;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setFont(parent.getFont());
// explicitly call super's cMA, which does something:
super.createMessageArea(composite);
// add text filter:
StructuredViewerFilterer textFilter = new StructuredViewerTextFilterer(StructuredViewerTextFilterer.DEFAULT_PROMPT,
StructuredViewerTextFilterer.DEFAULT_CLEAR,
new DatatypeLabelProvider(0));
textFilter.setDelayTime(50);
Control filterCtrl = textFilter.addControl(composite);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
gd.verticalIndent = 5;
filterCtrl.setLayoutData(gd);
// add ent. type filter:
filterCtrl = entFilter.addControl(composite);
gd = new GridData(SWT.FILL, SWT.FILL, true, false);
filterCtrl.setLayoutData(gd);
// allow super to create stuff:
Composite superComp = (Composite)super.createDialogArea(composite);
layout = (GridLayout)superComp.getLayout();
layout.marginHeight = 5;
layout.marginWidth = 0;
TableViewer tableViewer = getTableViewer();
GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, 200).applyTo(tableViewer.getControl());
tableViewer.getTable().setHeaderVisible(true);
tableViewer.getTable().setLinesVisible(true);
// create columns
TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.LEFT);
column.getColumn().setText("Design-time Type"); //$NON-NLS-1$
column.setLabelProvider(new DatatypeLabelProvider(0));
column.getColumn().setWidth(140);
column = new TableViewerColumn(tableViewer, SWT.LEFT);
column.getColumn().setText("Run-time Type" + " "); //$NON-NLS-1$
column.setLabelProvider(new DatatypeLabelProvider(1));
column.getColumn().setWidth(140);
column = new TableViewerColumn(tableViewer, SWT.LEFT);
column.getColumn().setText("Base Type" + " "); //$NON-NLS-1$
column.setLabelProvider(new DatatypeLabelProvider(2));
column.getColumn().setWidth(140);
// attach the filters:
textFilter.attachToViewer(tableViewer, true);
entFilter.attachToViewer(tableViewer, true);
// Added 9/27/04 to allow the SetDatatypeAction to retrieve a length value
// for a datatype of 'string'.
// To enable, the dialog must have the setEditLength(true) called before dialog.open()
// and an initial length value set via setInitialLength(int). Default length = 0
// If visible, spinner will disable for non-string types
if (editLength) {
Group lengthGroup = WidgetFactory.createGroup(composite, getString("lengthOptions"), //$NON-NLS-1$
GridData.FILL_HORIZONTAL,
1,
2);
WidgetFactory.createLabel(lengthGroup, GridData.FILL, getString("stringLengthLabel")); //$NON-NLS-1$
// int spinner
ispin = new Spinner(lengthGroup, SWT.BORDER);
ispin.setMinimum(MIN);
ispin.setMaximum(MAX);
ispin.setToolTipText(UiConstants.Util.getString(PREFIX + "lengthSpinner.toolTip", //$NON-NLS-1$
ispin.getMinimum(),
ispin.getMaximum()));
ispin.addModifyListener(new ModifyListener() {
@Override
public void modifyText( ModifyEvent theEvent ) {
setLength();
}
});
GridData gridData2 = new GridData();
gridData2.horizontalAlignment = GridData.CENTER;
gridData2.widthHint = 100;
ispin.setLayoutData(gridData2);
ispin.setSelection(initialLength);
ispin.setEnabled(true);
if (multipleObjects) {
setLengthForAllCheckBox = WidgetFactory.createCheckBox(lengthGroup, getString("setLengthForAll"), //$NON-NLS-1$
GridData.FILL,
2,
setLengthForAll);
setLengthForAllCheckBox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent ev ) {
setLengthForAll = setLengthForAllCheckBox.getSelection();
}
});
editLength = setLengthForAllCheckBox.getSelection();
} else {
setLengthForAll = true;
}
}
Group group = WidgetFactory.createGroup(composite, PATH_GROUP_TITLE, GridData.FILL_BOTH);
pathLabel = new CLabel(group, SWT.NONE);
pathLabel.setFont(composite.getFont());
pathLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// initialize path label text
List initialSelections = getInitialElementSelections();
if ((initialSelections != null) && !initialSelections.isEmpty() && (initialSelections.get(0) instanceof EObject)) {
this.pathLabel.setText(constructPath((EObject)initialSelections.get(0)));
}
return composite;
}
void setLength() {
this.currentLength = this.ispin.getSelection();
}
public int getLength() {
return this.currentLength;
}
public void setInitialLength( int newLength ) {
initialLength = newLength;
}
/**
* @param editLength The editLength to set.
* @since 4.2
*/
public void setEditLength( boolean editLength ) {
this.editLength = editLength;
}
void updateSpinner( ISelection selection ) {
// The spinner needs to be disabled when any type other than "string" is specified
if (ispin != null) {
boolean enable = false;
Object result = SelectionUtilities.getSelectedObject(selection);
if (typeIsString(result)) enable = true;
ispin.setEnabled(enable);
if (setLengthForAllCheckBox != null) {
setLengthForAllCheckBox.setEnabled(enable);
}
}
}
private boolean typeIsString( Object type ) {
if (type != null && type instanceof XSDSimpleTypeDefinition) {
String simpleType = ModelerCore.getWorkspaceDatatypeManager().getRuntimeTypeName((EObject)type);
if (simpleType.equalsIgnoreCase(STRING_STRING)) {
return true;
}
}
return false;
}
String constructPath( EObject eo ) {
IPath result = null;
String sPath;
if (isBuiltin(eo)) {
sPath = BUILT_IN + ONE_SPACE + ModelerCore.getModelEditor().getName(eo);
} else if (ModelUtil.isXsdFile(eo.eResource())) {
result = ModelerCore.getModelEditor().getModelRelativePath(eo);
sPath = result.toString();
} else {
result = ModelerCore.getModelEditor().getModelRelativePathIncludingModel(eo);
sPath = result.toString();
}
return sPath;
}
private boolean isBuiltin( EObject eo ) {
boolean bResult = false;
if (eo instanceof XSDSimpleTypeDefinition) {
try {
// Only care about built-in types, so just use the workspace DT Mgr ...
if (ModelerCore.getWorkspaceDatatypeManager().isBuiltInDatatype(eo)) {
bResult = true;
} else {
bResult = false;
}
} catch (Exception e) {
bResult = false;
}
}
return bResult;
}
/**
* @param theMultipleObjects The multipleObjects to set.
* @since 5.0
*/
public void setMultipleObjects( boolean theMultipleObjects ) {
this.multipleObjects = theMultipleObjects;
}
/**
* @return Returns the editLengthEnabled.
* @since 5.0
*/
public boolean overrideAllLengths() {
return this.setLengthForAll;
}
class DatatypeLabelProvider extends ColumnLabelProvider {
private final DatatypeManager datatypeManager = ModelerCore.getBuiltInTypesManager();
private final int columnNumber;
public DatatypeLabelProvider(int columnNumber) {
this.columnNumber = columnNumber;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
*/
@Override
public String getText(Object element) {
if( element instanceof EObject ) {
switch (this.columnNumber) {
case 0: {
String name = getDesignTimeTypeName((EObject)element);
if( name.equalsIgnoreCase("integer")) {
name = name + " <deprecated>";
}
return name;
}
case 1: {
String name = ModelerCore.getModelEditor().getName((EObject)element);
EObject designTimeType = null;
try {
designTimeType = datatypeManager.getBuiltInDatatype(name);
} catch (ModelerCoreException ex) {
// Nothing to do
}
if( designTimeType != null ) {
String runtimeTypename = datatypeManager.getRuntimeTypeName(designTimeType);
return runtimeTypename;
}
break;
}
case 2: {
return getBaseTypeName((EObject)element);
}
}
}
return EMPTY_STRING;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipText(java.lang.Object)
*/
@Override
public String getToolTipText(Object element) {
switch (this.columnNumber) {
case 0: {
return "Tooltip 1"; //getString("columnNameColumnTooltip"); //$NON-NLS-1$
}
case 1: {
return "Tooltip 2"; //getString("datatypeColumnTooltip"); //$NON-NLS-1$
}
}
return "unknown tooltip"; //$NON-NLS-1$
}
@Override
public Image getImage(Object element) {
if( this.columnNumber == 0 ) {
return ModelUtilities.getEMFLabelProvider().getImage(element);
}
return null;
}
private String getDesignTimeTypeName(EObject eObject) {
String rawName = ModelUtilities.getEMFLabelProvider().getText(eObject);
int colonIndex = rawName.indexOf(':');
if( colonIndex == -1 ) return rawName;
return rawName.substring(0, colonIndex).trim();
}
private String getBaseTypeName(EObject eObject) {
String rawName = ModelUtilities.getEMFLabelProvider().getText(eObject);
int colonIndex = rawName.indexOf(':');
int fullLength = rawName.length();
if( colonIndex == -1 ) return rawName;
return rawName.substring(colonIndex+1, fullLength).trim();
}
}
}