/*
* 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.builder.criteria;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.query.IQueryService;
import org.teiid.designer.query.sql.ISQLStringVisitor;
import org.teiid.designer.query.sql.lang.ICommand;
import org.teiid.designer.query.sql.lang.IExpression;
import org.teiid.designer.query.sql.lang.ILanguageObject;
import org.teiid.designer.query.sql.lang.ISetCriteria;
import org.teiid.designer.transformation.ui.builder.ExpressionBuilder;
import org.teiid.designer.transformation.ui.builder.actions.AddSetCriteriaItemAction;
import org.teiid.designer.transformation.ui.builder.actions.DeleteSetCriteriaItemAction;
import org.teiid.designer.transformation.ui.builder.actions.EditSetCriteriaItemAction;
import org.teiid.designer.ui.common.util.UiUtil;
import org.teiid.query.ui.UiPlugin;
import org.teiid.query.ui.builder.model.ILanguageObjectEditorModelListener;
import org.teiid.query.ui.builder.model.LanguageObjectEditorModelEvent;
import org.teiid.query.ui.builder.model.SetCriteriaEditorModel;
import org.teiid.query.ui.builder.util.ElementViewerFactory;
/**
* @since 8.0
*/
public class SetCriteriaEditor extends AbstractPredicateCriteriaTypeEditor {
private final static String PREFIX = I18nUtil.getPropertyPrefix(SetCriteriaEditor.class);
private final static int HORIZONTAL_GAP_BETWEEN_BUTTONS = 7;
private ISetCriteria setCriteria;
private CriteriaExpressionEditor editor;
private Control component;
SetCriteriaEditorModel theModel;
private ViewController viewController;
Button listButton;
private MenuManager listButtonMenuManager;
private AddSetCriteriaItemAction addAction;
private EditSetCriteriaItemAction editAction;
private DeleteSetCriteriaItemAction deleteAction;
Button subqueryButton;
private Composite stackedComposite;
private Composite listComposite;
private SashForm subquerySashForm;
private Text subquerySQLText;
private TreeViewer subqueryTreeViewer;
private Tree subqueryTree;
private StackLayout stackLayout;
private List curItemsList;
private Map listItemToLangObjMap = new HashMap();
private ILanguageObject[] objectsToSelect = new ILanguageObject[] {};
private int curType = -1; // SetCriteriaEditorModel.LIST or
// SetCriteriaEditorModel.SUBQUERY.
// -1 is initial value.
public SetCriteriaEditor( Composite parent,
SetCriteriaEditorModel model ) {
super(parent, ISetCriteria.class, model);
this.theModel = model;
this.viewController = new ViewController();
theModel.addModelListener(viewController);
this.viewController.initialize();
}
@Override
public String getToolTipText() {
String tip = Util.getString(PREFIX + "toolTipText"); //$NON-NLS-1$
return tip;
}
@Override
public String getTitle() {
String title = Util.getString(PREFIX + "title"); //$NON-NLS-1$
return title;
}
@Override
public Control createLeftComponent( Composite parent ) {
editor = new CriteriaExpressionEditor(parent, theModel.getExpressionModel());
component = editor.getUi();
return component;
}
@Override
public Control createRightComponent( Composite parent ) {
ViewForm rightComponentViewForm = new ViewForm(parent, SWT.BORDER);
Composite rightComponent = new Composite(rightComponentViewForm, SWT.NONE);
rightComponentViewForm.setContent(rightComponent);
GridLayout layout = new GridLayout();
rightComponent.setLayout(layout);
Composite topButtonPanel = new Composite(rightComponent, SWT.NONE);
RowLayout topButtonPanelLayout = new RowLayout();
topButtonPanelLayout.wrap = false;
topButtonPanelLayout.pack = true;
topButtonPanelLayout.justify = false;
topButtonPanelLayout.type = SWT.HORIZONTAL;
topButtonPanelLayout.spacing = HORIZONTAL_GAP_BETWEEN_BUTTONS;
topButtonPanel.setLayout(topButtonPanelLayout);
GridData topButtonPanelGridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
topButtonPanel.setLayoutData(topButtonPanelGridData);
listButton = new Button(topButtonPanel, SWT.RADIO);
String listButtonText = Util.getString(PREFIX + "list"); //$NON-NLS-1$
listButton.setText(listButtonText);
String listButtonToolTipText = Util.getString(PREFIX + "listToolTipText"); //$NON-NLS-1$
listButton.setToolTipText(listButtonToolTipText);
listButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent ev ) {
if (listButton.getSelection()) {
theModel.setCurType(SetCriteriaEditorModel.LIST);
}
}
});
subqueryButton = new Button(topButtonPanel, SWT.RADIO);
String subqueryButtonText = Util.getString(PREFIX + "subquery"); //$NON-NLS-1$
subqueryButton.setText(subqueryButtonText);
String subqueryButtonToolTipText = Util.getString(PREFIX + "subqueryToolTipText"); //$NON-NLS-1$
subqueryButton.setToolTipText(subqueryButtonToolTipText);
subqueryButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent ev ) {
if (subqueryButton.getSelection()) {
theModel.setCurType(SetCriteriaEditorModel.SUBQUERY);
}
}
});
stackedComposite = new Composite(rightComponent, SWT.NONE);
GridData stackedCompositeGridData = new GridData(GridData.FILL_BOTH);
stackedComposite.setLayoutData(stackedCompositeGridData);
stackLayout = new StackLayout();
stackedComposite.setLayout(stackLayout);
listComposite = new Composite(stackedComposite, SWT.NONE);
subquerySashForm = new SashForm(stackedComposite, SWT.VERTICAL);
GridLayout listCompositeLayout = new GridLayout();
listComposite.setLayout(listCompositeLayout);
curItemsList = new List(listComposite, SWT.MULTI);
GridData curItemsListGridData = new GridData(GridData.FILL_BOTH);
curItemsList.setLayoutData(curItemsListGridData);
curItemsList.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent ev ) {
curItemsListChanged();
}
});
// Override setEnabled() to prevent problems of WidgetUtil.setEnabled() disabling these
// buttons.
Composite buttonsPanel = new Composite(listComposite, SWT.NONE) {
@Override
public void setEnabled( boolean enabled ) {
super.setEnabled(enabled);
curItemsListChanged();
}
};
RowLayout buttonsPanelLayout = new RowLayout();
buttonsPanelLayout.wrap = false;
buttonsPanelLayout.pack = false;
buttonsPanelLayout.justify = false;
buttonsPanelLayout.type = SWT.HORIZONTAL;
buttonsPanelLayout.spacing = HORIZONTAL_GAP_BETWEEN_BUTTONS;
buttonsPanel.setLayout(buttonsPanelLayout);
GridData buttonsPanelGridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
buttonsPanel.setLayoutData(buttonsPanelGridData);
Runnable addRunnable = new Runnable() {
@Override
public void run() {
addButtonPressed();
}
};
addAction = new AddSetCriteriaItemAction(buttonsPanel, addRunnable);
addAction.setEnabled(true);
Runnable editRunnable = new Runnable() {
@Override
public void run() {
editButtonPressed();
}
};
editAction = new EditSetCriteriaItemAction(buttonsPanel, editRunnable);
editAction.setEnabled(false);
Runnable deleteRunnable = new Runnable() {
@Override
public void run() {
deleteButtonPressed();
}
};
deleteAction = new DeleteSetCriteriaItemAction(buttonsPanel, deleteRunnable);
deleteAction.setEnabled(false);
listButtonMenuManager = new MenuManager();
listButtonMenuManager.setRemoveAllWhenShown(true);
listButtonMenuManager.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow( IMenuManager menuMgr ) {
fillListButtonMenu();
}
});
listButton.setMenu(listButtonMenuManager.createContextMenu(listButton));
subquerySQLText = new Text(subquerySashForm, SWT.MULTI | SWT.WRAP | SWT.BORDER);
GridData sqlTextData = new GridData(GridData.FILL_HORIZONTAL);
subquerySQLText.setBackground(UiUtil.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
subquerySQLText.setForeground(UiUtil.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
subquerySQLText.setLayoutData(sqlTextData);
subqueryTreeViewer = ElementViewerFactory.createElementViewer(subquerySashForm);
subqueryTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick( DoubleClickEvent theEvent ) {
handleDoubleClick();
}
});
theModel.setViewer(subqueryTreeViewer);
subqueryTree = subqueryTreeViewer.getTree();
subqueryTree.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected( SelectionEvent theEvent ) {
handleTreeSelection();
}
@Override
public void widgetSelected( SelectionEvent theEvent ) {
handleTreeSelection();
}
});
GridData treeData = new GridData(GridData.FILL_BOTH);
subqueryTree.setLayoutData(treeData);
subquerySashForm.setWeights(new int[] {1, 3});
return rightComponentViewForm;
}
void fillListButtonMenu() {
listButtonMenuManager.add(addAction);
listButtonMenuManager.add(editAction);
listButtonMenuManager.add(deleteAction);
}
private void listTypeSelected() {
if (listButton.getSelection()) {
if (subqueryButton.getSelection()) {
subqueryButton.setSelection(false);
}
stackLayout.topControl = listComposite;
stackedComposite.layout();
theModel.setCurType(SetCriteriaEditorModel.LIST);
} else if (!subqueryButton.getSelection()) {
// Do not allow user to unset list button if subquery button not set
listButton.setSelection(true);
}
}
private void subqueryTypeSelected() {
if (subqueryButton.getSelection()) {
if (listButton.getSelection()) {
listButton.setSelection(false);
}
stackLayout.topControl = subquerySashForm;
stackedComposite.layout();
theModel.setCurType(SetCriteriaEditorModel.SUBQUERY);
} else if (!listButton.getSelection()) {
// Do not allow user to unset subquery button is list button not set
subqueryButton.setSelection(true);
}
}
void curItemsListChanged() {
// Add button always stays enabled
// Edit button enabled iff. exactly one item selected
// Delete button enabled iff. one or more items selected
int selectionCount = curItemsList.getSelectionCount();
editAction.setEnabled((selectionCount == 1));
deleteAction.setEnabled((selectionCount > 0));
}
void addButtonPressed() {
Shell shell = UiPlugin.getDefault().getCurrentWorkbenchWindow().getShell();
ExpressionBuilder expBld = new ExpressionBuilder(shell);
int returnCode = expBld.open();
if (returnCode == Window.OK) {
// Do not need to change either curItemsList or listItemToLangObjMap. We will do this when
// we receive an event telling us that the values have been changed.
ILanguageObject langObj = expBld.getLanguageObject();
objectsToSelect = new ILanguageObject[] {langObj};
theModel.addValue(langObj);
}
}
void editButtonPressed() {
// Can only be one item selected or edit button is disabled.
String listItem = curItemsList.getSelection()[0];
ILanguageObject obj = (ILanguageObject)listItemToLangObjMap.get(listItem);
Shell shell = UiPlugin.getDefault().getCurrentWorkbenchWindow().getShell();
ExpressionBuilder expBld = new ExpressionBuilder(shell);
// Not certain why a create() call is necessary here but it seems to be. BWP 08/26/03
expBld.create();
expBld.setLanguageObject(obj);
int returnCode = expBld.open();
if (returnCode == Window.OK) {
ILanguageObject newObj = expBld.getLanguageObject();
if (!obj.equals(newObj)) {
// Do not need to change either curItemsList or
// listItemToLangObjMap. We will do this when we receive an event
// telling us that the values have been changed.
objectsToSelect = new ILanguageObject[] {newObj};
theModel.replaceValue(obj, newObj);
}
}
}
void deleteButtonPressed() {
// We will replace the entire set of values in the model, with those not selected in curItemsList
int[] selectedIndices = curItemsList.getSelectionIndices();
int itemCount = curItemsList.getItemCount();
boolean[] stillIncludedMask = new boolean[itemCount];
for (int i = 0; i < itemCount; i++) {
stillIncludedMask[i] = true;
}
for (int i = 0; i < selectedIndices.length; i++) {
stillIncludedMask[selectedIndices[i]] = false;
}
// Collect up only those items that were not selected in curItemsList
Collection newValues = new ArrayList(itemCount);
for (int i = 0; i < itemCount; i++) {
if (stillIncludedMask[i]) {
String listItem = curItemsList.getItem(i);
ILanguageObject obj = (ILanguageObject)listItemToLangObjMap.get(listItem);
newValues.add(obj);
}
}
// Do not need to change either curItemsList or listItemToLangObjMap. We will do this when
// we receive an event telling us that the values have been changed.
objectsToSelect = new ILanguageObject[] {};
theModel.setValues(newValues);
}
@Override
public IExpression getLeftExpression() {
IExpression leftExpression = null;
if (setCriteria != null) {
leftExpression = setCriteria.getExpression();
}
return leftExpression;
}
@Override
public IExpression getRightExpression() {
// Unused
return null;
}
@Override
public void setLanguageObject( ILanguageObject obj ) {
CoreArgCheck.isInstanceOf(ISetCriteria.class, obj);
setCriteria = (ISetCriteria)obj;
editor.setLanguageObject(getLeftExpression());
}
@Override
public String[] getOperators() {
return theModel.getOperators();
}
@Override
public void acceptFocus() {
editor.acceptFocus();
}
@Override
public void setOperator( String op ) {
theModel.setCurrentOperator(op);
}
@Override
public String getCurrentOperator() {
return theModel.getCurrentOperator();
}
void handleDoubleClick() {
// Is there anything to do here?
}
void handleTreeSelection() {
IStructuredSelection selection = (IStructuredSelection)subqueryTreeViewer.getSelection();
Object firstSelection = selection.getFirstElement();
theModel.setSubquerySelection(firstSelection);
}
void displayExpression() {
}
void displayValues() {
if (curType == SetCriteriaEditorModel.LIST) {
curItemsList.removeAll();
listItemToLangObjMap.clear();
ISetCriteria setCriteria = (ISetCriteria)theModel.getLanguageObject();
Collection newValues = setCriteria.getValues();
// Put the list of values into curItemsList and into listItemToLangObjMap
Iterator it = newValues.iterator();
while (it.hasNext()) {
ILanguageObject langObj = (ILanguageObject)it.next();
String itemName = langObj.toString();
curItemsList.add(itemName);
listItemToLangObjMap.put(itemName, langObj);
}
// Now select those items in the list that we have already flagged
Collection selectionLocs = new ArrayList();
for (int i = 0; i < objectsToSelect.length; i++) {
int index = curItemsList.indexOf(objectsToSelect[i].toString());
if (index >= 0) {
selectionLocs.add(new Integer(index));
}
}
int[] selectionLocsArray = new int[selectionLocs.size()];
it = selectionLocs.iterator();
for (int i = 0; it.hasNext(); i++) {
Integer tempInt = (Integer)it.next();
selectionLocsArray[i] = tempInt.intValue();
}
curItemsList.select(selectionLocsArray);
curItemsListChanged();
}
}
void displayType() {
int newType = theModel.getCurType();
if (newType != curType) {
curType = newType;
if (curType == SetCriteriaEditorModel.LIST) {
if (!listButton.getSelection()) {
listButton.setSelection(true);
}
listTypeSelected();
} else { // must be SUBQUERY
if (!subqueryButton.getSelection()) {
subqueryButton.setSelection(true);
}
subqueryTypeSelected();
}
}
}
void displayCommand() {
ICommand command = theModel.getCommand();
String displayText;
if (command == null) {
Object selection = theModel.getSubquerySelection();
if (selection == null) {
displayText = Util.getString(PREFIX + "noSelectionMsg"); //$NON-NLS-1$
} else {
displayText = theModel.getInvalidSelectionMessage();
}
} else {
IQueryService queryService = ModelerCore.getTeiidQueryService();
ISQLStringVisitor visitor = queryService.getSQLStringVisitor();
displayText = visitor.returnSQLString(command);
}
subquerySQLText.setText(displayText);
}
void displayLanguageObjectChange() {
displayType();
displayExpression();
displayValues();
displayCommand();
}
/**
* The <code>ViewController</code> class is a view controller for the <code>FunctionEditor</code>.
*/
private class ViewController implements ILanguageObjectEditorModelListener {
public ViewController() {
super();
}
public void initialize() {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
modelChanged(new LanguageObjectEditorModelEvent(theModel, LanguageObjectEditorModelEvent.SAVED));
}
});
}
/**
* @see org.teiid.query.ui.builder.model.ILanguageObjectEditorModelListener#modelChanged(org.teiid.query.ui.builder.model.LanguageObjectEditorModelEvent)
*/
@Override
public void modelChanged( LanguageObjectEditorModelEvent theEvent ) {
String type = theEvent.getType();
if (type.equals(SetCriteriaEditorModel.EXPRESSION)) {
displayExpression();
} else if (type.equals(SetCriteriaEditorModel.VALUES)) {
displayValues();
} else if (type.equals(SetCriteriaEditorModel.COMMAND)) {
displayCommand();
} else if (type.equals(SetCriteriaEditorModel.SUBTYPE_CHANGED)) {
displayType();
} else if (type.equals(LanguageObjectEditorModelEvent.SAVED)) {
displayLanguageObjectChange();
}
}
}
}// end SetCriteriaEditor