/* * 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.transformation.ui.reconciler; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; 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.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.query.IQueryService; import org.teiid.designer.query.sql.lang.IExpression; import org.teiid.designer.transformation.ui.UiConstants; import org.teiid.designer.transformation.ui.UiPlugin; import org.teiid.designer.transformation.util.TransformationMappingHelper; import org.teiid.designer.transformation.util.TransformationSqlHelper; import org.teiid.designer.ui.common.table.TableSizeAdapter; import org.teiid.designer.ui.common.util.WidgetFactory; import org.teiid.designer.ui.common.widget.Label; /** * BindingsTable * * @since 8.0 */ public class SqlTablePanel extends Composite { // Style Contants static final int LABEL_GRID_STYLE = GridData.HORIZONTAL_ALIGN_BEGINNING; private static final int BUTTON_GRID_STYLE = GridData.HORIZONTAL_ALIGN_CENTER; private static final String SORT_BUTTON_TEXT = UiConstants.Util.getString("SqlTablePanel.sortButton.text"); //$NON-NLS-1$ private static final String UNSORT_BUTTON_TEXT = UiConstants.Util.getString("SqlTablePanel.unsortButton.text"); //$NON-NLS-1$ // Create a SqlList and assign it to an instance variable SqlList sqlList = new SqlList(); // Keep list of original symbol names to remember original order. private List originalSymbolNames; private List availableSymbolNames; private Table table; TableViewer tableViewer; private Button removeButton; private Button clearButton; private Button addButton; private Button sortButton; private boolean isReadOnly = false; private boolean bUseOriginalOrder = true; private ViewerSorter viewerSorter; /** * Constructor. * * @param parent Parent of this control */ public SqlTablePanel( Composite parent ) { super(parent, SWT.NONE); init(); } /** * Constructor. * * @param parent Parent of this control */ public SqlTablePanel( Composite parent, boolean isReadOnly ) { super(parent, SWT.NONE); this.isReadOnly = isReadOnly; init(); } /** * Initialize the panel. */ private void init() { // ------------------------------ // Set layout for the Composite // ------------------------------ GridLayout gridLayout = new GridLayout(); this.setLayout(gridLayout); gridLayout.numColumns = 1; GridData gridData = new GridData(GridData.FILL_BOTH); gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; this.setLayoutData(gridData); WidgetFactory.createLabel(this, LABEL_GRID_STYLE, 1, UiConstants.Util.getString("SqlTablePanel.sqlList.title")); //$NON-NLS-1$ // ---------------------------------- // Create the Table Viewer Panel // ---------------------------------- createTable(this); // -------------------------------------- // Create the Control Button Composite // -------------------------------------- createControlButtonPanel(); // Init button enable states setButtonStates(); } /** * Initialize the panel. */ private void createControlButtonPanel() { Composite buttonComposite = new Composite(this, SWT.NONE); // ------------------------------ // Set layout for the Composite // ------------------------------ GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 9; gridLayout.horizontalSpacing = 0; gridLayout.marginWidth = 0; buttonComposite.setLayout(gridLayout); GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); buttonComposite.setLayoutData(gridData); addButton = WidgetFactory.createButton(buttonComposite, BUTTON_GRID_STYLE); // UiConstants.Util.getString("SqlTablePanel.addButton.text"), BUTTON_GRID_STYLE); //$NON-NLS-1$ addButton.setImage(UiPlugin.getDefault().getImage(UiConstants.Images.ADD_ICON)); addButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected( final SelectionEvent event ) { addButtonPressed(); } }); removeButton = WidgetFactory.createButton(buttonComposite, BUTTON_GRID_STYLE); //UiConstants.Util.getString("SqlTablePanel.removeSqlButton.text"), BUTTON_GRID_STYLE); //$NON-NLS-1$ removeButton.setImage(UiPlugin.getDefault().getImage(UiConstants.Images.REMOVE_ICON)); removeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected( final SelectionEvent event ) { removeSqlButtonPressed(); } }); clearButton = WidgetFactory.createButton(buttonComposite, BUTTON_GRID_STYLE); // UiConstants.Util.getString("SqlTablePanel.clearButton.text"), BUTTON_GRID_STYLE); //$NON-NLS-1$ clearButton.setImage(UiPlugin.getDefault().getImage(UiConstants.Images.CLEAR_ICON)); clearButton.setToolTipText(UiConstants.Util.getString("SqlTablePanel.clearButton.text")); clearButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected( final SelectionEvent event ) { clearButtonPressed(); } }); // jh Defect 21404: Add sort button sortButton = WidgetFactory.createButton(buttonComposite, SORT_BUTTON_TEXT, BUTTON_GRID_STYLE); GridDataFactory.swtDefaults().hint(36, 28).grab(true, true).applyTo(sortButton); sortButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected( final SelectionEvent event ) { sortButtonPressed(); } }); // GridData gridData2 = (GridData)sortButton.getLayoutData(); // // gridData2.widthHint = 45; // sortButton.setLayoutData(gridData2); } /** * Create the Table */ private void createTable( final Composite parent ) { int style = SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION; table = new Table(parent, style); GridData gridData = new GridData(GridData.FILL_BOTH); gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; table.setLayoutData(gridData); table.setLinesVisible(true); table.setHeaderVisible(true); TableLayout layout = new TableLayout(); table.setLayout(layout); // 1st column with attribute TableColumn column1 = new TableColumn(table, SWT.LEFT, 0); column1.setText(UiConstants.Util.getString("SqlTablePanel.sqlList.column.text")); //$NON-NLS-1$ ColumnWeightData weight = new ColumnWeightData(1); layout.addColumnData(weight); tableViewer = new TableViewer(table); tableViewer.setContentProvider(new SqlContentProvider()); tableViewer.setLabelProvider(new SqlLabelProvider()); tableViewer.setInput(sqlList); tableViewer.getTable().setHeaderVisible(false); createTableTooltipListeners(table); // add a listener to keep the table sized to it's container new TableSizeAdapter(table, 10); } /** * Setup listeners for table tooltips */ private void createTableTooltipListeners( final Table table ) { // Disable native tooltip table.setToolTipText(""); //$NON-NLS-1$ // Implement a "fake" tooltip final Listener labelListener = new Listener() { @Override public void handleEvent( Event event ) { Label label = (Label)event.widget; Shell shell = label.getShell(); switch (event.type) { case SWT.MouseDown: Event e = new Event(); e.item = (TableItem)label.getData("_TABLEITEM"); //$NON-NLS-1$ // Assuming table is single select, set the selection as if // the mouse down event went through to the table table.setSelection(new TableItem[] {(TableItem)e.item}); table.notifyListeners(SWT.Selection, e); shell.dispose(); break; case SWT.MouseExit: shell.dispose(); break; } } }; Listener tableListener = new Listener() { Shell tip = null; Label label = null; @Override public void handleEvent( Event event ) { switch (event.type) { case SWT.Dispose: case SWT.KeyDown: case SWT.MouseMove: { if (tip == null) break; tip.dispose(); tip = null; label = null; break; } case SWT.MouseHover: { TableItem item = table.getItem(new Point(event.x, event.y)); if (item != null) { if (tip != null && !tip.isDisposed()) tip.dispose(); tip = new Shell(getShell(), SWT.ON_TOP); tip.setLayout(new FillLayout()); label = new Label(tip, SWT.NONE); label.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND)); label.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); label.setData("_TABLEITEM", item); //$NON-NLS-1$ Object data = item.getData(); String tipText = null; if (data instanceof IExpression) { IQueryService queryService = ModelerCore.getTeiidQueryService(); tipText = queryService.getSymbolName(((IExpression)data)); } if (tipText != null) { label.setText(tipText); } label.addListener(SWT.MouseExit, labelListener); label.addListener(SWT.MouseDown, labelListener); Point size = tip.computeSize(SWT.DEFAULT, SWT.DEFAULT); Rectangle rect = item.getBounds(0); Point pt = table.toDisplay(rect.x, rect.y); tip.setBounds(pt.x + 10, pt.y + 10, size.x, size.y); tip.setVisible(true); } } } } }; table.addListener(SWT.Dispose, tableListener); table.addListener(SWT.KeyDown, tableListener); table.addListener(SWT.MouseMove, tableListener); table.addListener(SWT.MouseHover, tableListener); } /** * Handler for remove SQL Button */ void removeSqlButtonPressed() { // Save the last selection index int[] selectedIndices = table.getSelectionIndices(); int lastIndex = 0; if (selectedIndices.length > 0) { lastIndex = selectedIndices[selectedIndices.length - 1]; } // Remove Selections from the sqlList List selections = getSelectedSymbols(); if (!selections.isEmpty()) { sqlList.removeAll(selections); } // Reselect last index selectIndex(lastIndex); setButtonStates(); } /** * Handler for remove SQL Button */ void clearButtonPressed() { // Remove Selections from the sqlList List contents = new ArrayList(sqlList.getAll()); if (!contents.isEmpty()) { sqlList.removeAll(contents); } // Reselect last index selectIndex(0); setButtonStates(); } /** * Handler for remove SQL Button */ void addButtonPressed() { if (availableSymbolNames != null && !availableSymbolNames.isEmpty()) { AddSqlSymbolsDialog dialog = new AddSqlSymbolsDialog(getShell(), availableSymbolNames); int returnStatus = dialog.open(); if (returnStatus == Window.CANCEL) { return; } List newSymbols = dialog.getSelectedSymbols(); if (newSymbols != null && !newSymbols.isEmpty()) { // Save the last selection index int[] selectedIndices = table.getSelectionIndices(); int lastIndex = 0; if (selectedIndices.length > 0) { lastIndex = selectedIndices[selectedIndices.length - 1]; } // Find all symbols for language object sqlList.addAll(newSymbols); // Reselect last index selectIndex(lastIndex); setButtonStates(); } } } /** * Handler for remove SQL Button */ void sortButtonPressed() { // 1. set the sort flag bUseOriginalOrder = !bUseOriginalOrder; // 2. change the sorter if (bUseOriginalOrder) { tableViewer.setSorter(null); } else { tableViewer.setSorter(getViewerSorter()); } setButtonStates(); } private ViewerSorter getViewerSorter() { if (viewerSorter == null) { viewerSorter = new ViewerSorter(); } return viewerSorter; } public void addTableSelectionListener( ISelectionChangedListener listener ) { tableViewer.addSelectionChangedListener(listener); } public void removeTableSelectionListener( ISelectionChangedListener listener ) { tableViewer.removeSelectionChangedListener(listener); } /** * Set Button States */ public void setButtonStates() { removeButton.setEnabled(true); clearButton.setEnabled(true); addButton.setEnabled(true); sortButton.setEnabled(true); if (isReadOnly) { removeButton.setEnabled(false); clearButton.setEnabled(false); addButton.setEnabled(false); return; } boolean tableIsEmpty = table.getItems() == null || table.getItems().length == 0; // -- update the sort button text (before we check the readonly flag) if (bUseOriginalOrder) { sortButton.setText(SORT_BUTTON_TEXT); } else { sortButton.setText(UNSORT_BUTTON_TEXT); } // Button enablements based on table content if (tableIsEmpty) { removeButton.setEnabled(false); clearButton.setEnabled(false); sortButton.setEnabled(false); } else { removeButton.setEnabled(table.getSelectionIndices().length > 0); } // Disable Add button if nothing to add if(this.availableSymbolNames==null || this.availableSymbolNames.isEmpty()) { addButton.setEnabled(false); } } /** * Return the TableViewer for the Sql Table Viewer */ public TableViewer getTableViewer() { return tableViewer; } /** * Set the SqlList */ public void setSqlList( SqlList list ) { this.sqlList = list; tableViewer = new TableViewer(table); tableViewer.setContentProvider(new SqlContentProvider()); tableViewer.setLabelProvider(new SqlLabelProvider()); tableViewer.setInput(sqlList); tableViewer.getTable().setHeaderVisible(false); // Builder originalSymbols list originalSymbolNames = new ArrayList(list.size()); for (int i = 0; i < list.size(); i++) { IExpression sym = list.getSymbolAt(i); String shortName = TransformationSqlHelper.getSingleElementSymbolShortName(sym, false); originalSymbolNames.add(shortName); } setButtonStates(); } /** * Return the SqlList */ public SqlList getSqlList() { return sqlList; } /** * Return the current selected symbols as a list */ public List getSelectedSymbols() { IStructuredSelection selection = (IStructuredSelection)tableViewer.getSelection(); return selection.toList(); } /** * add a Symbol to the list */ public void addSymbol( IExpression seSymbol ) { if (!sqlList.containsSymbol(seSymbol)) { // If symbol is in the original list, add it in the right place int index = getInsertIndex(seSymbol); sqlList.insert(seSymbol, index); } } /** * Get the Index for inserting a SQL element, based on the original SQL order. * * @param string the SQL element name * @return the index location to insert */ private int getInsertIndex( IExpression seSymbol ) { int index = sqlList.size(); IQueryService queryService = ModelerCore.getTeiidQueryService(); String suppliedName = queryService.getSymbolShortName(seSymbol); int nSymbols = sqlList.size(); for (int i = 0; i < nSymbols; i++) { IExpression currentSymbol = sqlList.getSymbolAt(i); String symbolName = queryService.getSymbolShortName(currentSymbol); if (isStringBefore(suppliedName, symbolName, originalSymbolNames)) { index = i; break; } } return index; } /** * Checks whether a string is before another string in a list. * * @param str1 the first string * @param str2 the second string * @param list the list * @return true if str1 is before str2, false if not. */ private boolean isStringBefore( String str1, String str2, List list ) { if (containsIgnoreCase(list, str1) && containsIgnoreCase(list, str2)) { int str1Index = indexOfIgnoreCase(list, str1); int str2Index = indexOfIgnoreCase(list, str2); return (str1Index < str2Index) ? true : false; } return false; } /** * this method checks whether the supplied Collection of Strings contains the supplied String, ignoring the case of the * strings. * * @param collection the collection of Strings to test. * @param string the string to test. * @return true if the collection contains the string, false if not. The case of the strings are ignored. */ private boolean containsIgnoreCase( Collection collection, String string ) { if (string == null) return false; Iterator iter = collection.iterator(); while (iter.hasNext()) { String collStr = (String)iter.next(); if (collStr != null && collStr.equalsIgnoreCase(string)) { return true; } } return false; } /** * this method gets the index of a supplied string within a supplied List, ignoring the case of the strings. * * @param list the List of Strings to test. * @param string the string to test. * @return the index of the supplied string in the list, -1 if its not in the list */ private int indexOfIgnoreCase( List list, String string ) { if (string == null || list == null) return -1; int nItems = list.size(); for (int i = 0; i < nItems; i++) { String listStr = (String)list.get(i); if (listStr != null && listStr.equalsIgnoreCase(string)) { return i; } } return -1; } /** * Select the Symbol at the supplied index. If the index does not exist, then select the first symbol in the list. * * @param index the index to select */ public void selectIndex( int index ) { IExpression nextSelection = sqlList.getSymbolAt(index); // If the index returned null, get the first symbol if (nextSelection == null) { nextSelection = sqlList.getFirstSymbol(); } // Set the selection if not null if (nextSelection != null) { tableViewer.setSelection(new StructuredSelection(nextSelection), true); } setButtonStates(); } /** * InnerClass that acts as a proxy for the BindingList providing content for the Table. It implements the IBindingListViewer * interface since it must register changeListeners with the BindingList */ class SqlContentProvider implements IStructuredContentProvider, ISqlListViewer { @Override public void inputChanged( Viewer v, Object oldInput, Object newInput ) { if (newInput != null) ((SqlList)newInput).addChangeListener(this); if (oldInput != null) ((SqlList)oldInput).removeChangeListener(this); } @Override public void dispose() { sqlList.removeChangeListener(this); } // Return the bindings as an array of Objects @Override public Object[] getElements( Object parent ) { return sqlList.getAll().toArray(); } /** * @see IBindingListViewer#addSymbol(SingleElementSymbol) */ @Override public void addSymbol( IExpression symbol ) { if (sqlList.containsSymbol(symbol)) tableViewer.add(symbol); } /** * @see IBindingListViewer#addSymbol(SingleElementSymbol) */ @Override public void insertSymbol( IExpression symbol, int index ) { if (sqlList.containsSymbol(symbol)) tableViewer.insert(symbol, index); } /** * @see IBindingListViewer#addSymbols(Object[]) */ @Override public void addSymbols( Object[] symbols ) { for (int i = 0; i < symbols.length; i++) { addSymbol((IExpression)symbols[i]); } } /** * @see IBindingListViewer#removeSymbol(SingleElementSymbol) */ @Override public void removeSymbol( IExpression symbol ) { tableViewer.remove(symbol); } /** * @see IBindingListViewer#removeSymbols(SingleElementSymbol[]) */ @Override public void removeSymbols( Object[] symbols ) { tableViewer.remove(symbols); } /** * @see IBindingListViewer#updateSymbols(SingleElementSymbol) */ @Override public void updateSymbol( IExpression symbol ) { tableViewer.update(symbol, null); } /** * @see IBindingListViewer#updateSymbols(SingleElementSymbol) */ @Override public void refresh( boolean updateLabels ) { tableViewer.refresh(updateLabels); } } public List getAvailableSymbolNames() { return this.availableSymbolNames; } public void setAvailableSymbolNames( List availableSymbolNames ) { this.availableSymbolNames = new ArrayList(availableSymbolNames); setButtonStates(); } public void preDispose( boolean allowCreateAttributes ) { if (!getSqlList().getAll().isEmpty()) { MyMessageDialog myDialog = new MyMessageDialog(getShell(), allowCreateAttributes); int result = myDialog.open(); boolean createAttributes = myDialog.getCreateAttributesState(); TransformationMappingHelper.setCreateTargetAttributes(createAttributes); if (result == Window.OK) { clearButtonPressed(); } } } class MyMessageDialog extends MessageDialog { public boolean createAttributesState = false; public boolean allowCreateAttributes = false; /** * @param theParentShell * @param theDialogTitle * @param theDialogTitleImage * @param theDialogMessage * @param theDialogImageType * @param theDialogButtonLabels * @param theDefaultIndex * @since 5.0 */ public MyMessageDialog( Shell theParentShell, boolean allowCreateAttributes ) { super(theParentShell, UiConstants.Util.getString("SqlTablePanel.myMessageDialog.title"), //$NON-NLS-1$ null, UiConstants.Util.getString("SqlTablePanel.myMessageDialog.message"), //$NON-NLS-1$ MessageDialog.QUESTION, new String[] {IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL}, 0); this.allowCreateAttributes = allowCreateAttributes; } @Override protected Control createCustomArea( Composite theParent ) { Group group = WidgetFactory.createGroup(theParent, UiConstants.Util.getString("SqlTablePanel.myMessageDialog.groupTitle"), //$NON-NLS-1$ GridData.FILL_BOTH); group.setLayoutData(new GridData(GridData.FILL_BOTH)); group.getBorderWidth(); if (allowCreateAttributes) { String theText = UiConstants.Util.getString("SqlTablePanel.myMessageDialog.createAttributesMessage"); //$NON-NLS-1$ WidgetFactory.createLabel(group, theText); final Button createAttributesOnExitButton = WidgetFactory.createButton(group, UiConstants.Util.getString("SqlTablePanel.createAttributesOnExitButton.text"), //$NON-NLS-1$ LABEL_GRID_STYLE, 1, SWT.CHECK); createAttributesOnExitButton.setSelection(false); createAttributesOnExitButton.setToolTipText(UiConstants.Util.getString("SqlTablePanel.createAttributesOnExitButton.toolTip")); //$NON-NLS-1$ createAttributesOnExitButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected( final SelectionEvent event ) { createAttributesState = createAttributesOnExitButton.getSelection(); } }); } return group; } public boolean getCreateAttributesState() { return createAttributesState; } } }