001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: */
013: package org.pentaho.designstudio.controls;
014:
015: import java.text.MessageFormat;
016: import java.util.ArrayList;
017: import java.util.Arrays;
018: import java.util.List;
019:
020: import org.eclipse.core.runtime.IStatus;
021: import org.eclipse.core.runtime.Status;
022: import org.eclipse.jface.dialogs.ErrorDialog;
023: import org.eclipse.jface.util.Assert;
024: import org.eclipse.jface.viewers.CellEditor;
025: import org.eclipse.jface.viewers.ICellModifier;
026: import org.eclipse.jface.viewers.IContentProvider;
027: import org.eclipse.jface.viewers.ILabelProviderListener;
028: import org.eclipse.jface.viewers.ITableLabelProvider;
029: import org.eclipse.jface.viewers.StructuredSelection;
030: import org.eclipse.jface.viewers.TextCellEditor;
031: import org.eclipse.swt.SWT;
032: import org.eclipse.swt.custom.CCombo;
033: import org.eclipse.swt.events.FocusAdapter;
034: import org.eclipse.swt.events.FocusEvent;
035: import org.eclipse.swt.events.KeyAdapter;
036: import org.eclipse.swt.events.KeyEvent;
037: import org.eclipse.swt.events.KeyListener;
038: import org.eclipse.swt.events.SelectionAdapter;
039: import org.eclipse.swt.events.SelectionEvent;
040: import org.eclipse.swt.events.TraverseEvent;
041: import org.eclipse.swt.events.TraverseListener;
042: import org.eclipse.swt.graphics.GC;
043: import org.eclipse.swt.graphics.Image;
044: import org.eclipse.swt.widgets.Composite;
045: import org.eclipse.swt.widgets.Control;
046: import org.eclipse.swt.widgets.Table;
047: import org.eclipse.swt.widgets.TableColumn;
048: import org.eclipse.swt.widgets.TableItem;
049: import org.eclipse.swt.widgets.Text;
050: import org.pentaho.actionsequence.dom.AbstractActionIOElement;
051: import org.pentaho.actionsequence.dom.AbstractIOElement;
052: import org.pentaho.actionsequence.dom.ActionInput;
053: import org.pentaho.actionsequence.dom.ActionSequenceDocument;
054: import org.pentaho.actionsequence.dom.IActionInputVariable;
055: import org.pentaho.designstudio.messages.Messages;
056:
057: /**
058: * Table viewer used for viewing and modifying the inputs of an action
059: * definition element.
060: *
061: * @author Angelo Rodriguez
062: */
063: public class GenericActionInputsTable extends ActionIOTable {
064:
065: static final String MAPPING_COLUMN_PROP = "MAPPING"; //$NON-NLS-1$
066:
067: static final int MAPPING_COLUMN_IDX = 2;
068:
069: InputNameCellEditor inputNameCellEditor;
070: InputTypeCellEditor inputTypeCellEditor;
071:
072: /**
073: * The editor used for changing input mappings.
074: */
075: protected InputMappingCellEditor inputMappingCellEditor;
076:
077: class InputMappingCellEditor extends CellEditor {
078: boolean valueChanged = false;
079:
080: boolean pressedReturn = false;
081:
082: private String[] items;
083:
084: int selection;
085:
086: CCombo comboBox;
087:
088: private static final int defaultStyle = SWT.NONE;
089:
090: public InputMappingCellEditor(Composite parent) {
091: super (parent, defaultStyle);
092: }
093:
094: public String[] getItems() {
095: return this .items;
096: }
097:
098: public void setItems(String[] items) {
099: Assert.isNotNull(items);
100: this .items = items;
101: populateComboBoxItems();
102: }
103:
104: protected Control createControl(Composite parent) {
105:
106: comboBox = new CCombo(parent, getStyle());
107: comboBox.setFont(parent.getFont());
108:
109: comboBox.addKeyListener(new KeyAdapter() {
110: // hook key pressed - see PR 14201
111: public void keyPressed(KeyEvent e) {
112: keyReleaseOccured(e);
113: }
114: });
115:
116: comboBox.addSelectionListener(new SelectionAdapter() {
117: public void widgetDefaultSelected(SelectionEvent event) {
118: pressedReturn = true;
119: applyEditorValueAndDeactivate();
120: }
121:
122: public void widgetSelected(SelectionEvent event) {
123: selection = comboBox.getSelectionIndex();
124: }
125: });
126:
127: comboBox.addTraverseListener(new TraverseListener() {
128: public void keyTraversed(TraverseEvent e) {
129: if (e.detail == SWT.TRAVERSE_ESCAPE
130: || e.detail == SWT.TRAVERSE_RETURN) {
131: e.doit = false;
132: }
133: }
134: });
135:
136: comboBox.addFocusListener(new FocusAdapter() {
137: public void focusLost(FocusEvent e) {
138: InputMappingCellEditor.this .focusLost();
139: }
140: });
141: return comboBox;
142: }
143:
144: /* (non-Javadoc)
145: * @see org.eclipse.jface.viewers.CellEditor#doGetValue()
146: */
147: protected Object doGetValue() {
148: Object value = null;
149: CCombo combo = (CCombo) getControl();
150: int selectedIdx = combo.getSelectionIndex();
151: if (selectedIdx >= 0) {
152: value = combo.getItem(selectedIdx);
153: }
154: return value;
155: }
156:
157: protected void doSetFocus() {
158: comboBox.setFocus();
159: }
160:
161: public LayoutData getLayoutData() {
162: LayoutData layoutData = super .getLayoutData();
163: if ((comboBox == null) || comboBox.isDisposed())
164: layoutData.minimumWidth = 60;
165: else {
166: // make the comboBox 10 characters wide
167: GC gc = new GC(comboBox);
168: layoutData.minimumWidth = (gc.getFontMetrics()
169: .getAverageCharWidth() * 10) + 10;
170: gc.dispose();
171: }
172: return layoutData;
173: }
174:
175: private void setAvailComboOptions(String typeOfInput) {
176: setItems(new String[0]);
177: if (typeOfInput != null) {
178: ArrayList items = new ArrayList();
179: if (actionDefinition != null) {
180: IActionInputVariable[] availInputs = actionDefinition
181: .getAvailInputVariables(typeOfInput);
182: for (int i = 0; i < availInputs.length; i++) {
183: items.add(ActionUtil
184: .parameterToDisplayText(availInputs[i]
185: .getVariableName()));
186: }
187: items.add(0, ""); //$NON-NLS-1$
188: }
189: setItems((String[]) items.toArray(new String[0]));
190: }
191: }
192:
193: protected void doSetValue(Object value) {
194: valueChanged = false;
195: pressedReturn = false;
196: String typeStr = null;
197:
198: if (value instanceof AbstractIOElement) {
199: AbstractIOElement inputElement = (AbstractIOElement) value;
200: typeStr = inputElement.getType();
201: }
202:
203: setAvailComboOptions(typeStr);
204:
205: String mapToName = ""; //$NON-NLS-1$
206: if (value instanceof ActionInput) {
207: ActionInput inputElement = (ActionInput) value;
208: mapToName = inputElement.getMapping();
209: if (mapToName.trim().length() != 0) {
210: mapToName = ActionUtil
211: .parameterToDisplayText(mapToName);
212: }
213: }
214:
215: CCombo combo = (CCombo) getControl();
216: combo.setText(mapToName);
217: }
218:
219: private void populateComboBoxItems() {
220: if (comboBox != null && items != null) {
221: comboBox.removeAll();
222: for (int i = 0; i < items.length; i++)
223: comboBox.add(items[i], i);
224:
225: setValueValid(true);
226: selection = 0;
227: }
228: }
229:
230: void applyEditorValueAndDeactivate() {
231: selection = comboBox.getSelectionIndex();
232: Object newValue = doGetValue();
233: markDirty();
234: boolean isValid = isCorrect(newValue);
235: setValueValid(isValid);
236: if (!isValid) {
237: // try to insert the current value into the error message.
238: setErrorMessage(MessageFormat.format(getErrorMessage(),
239: new Object[] { items[selection] }));
240: }
241: fireApplyEditorValue();
242: deactivate();
243: }
244:
245: protected void focusLost() {
246: if (isActivated()) {
247: applyEditorValueAndDeactivate();
248: }
249: }
250:
251: protected void keyReleaseOccured(KeyEvent keyEvent) {
252: if (keyEvent.character == '\u001b') { // Escape character
253: fireCancelEditor();
254: } else if (keyEvent.character == '\t') { // tab key
255: applyEditorValueAndDeactivate();
256: }
257: }
258:
259: public void deactivate() {
260: // TODO Auto-generated method stub
261: super .deactivate();
262: if (valueChanged) {
263: valueChanged = false;
264: int selectedIndex = getTable().getSelectionIndex();
265: TableItem tableItem = getTable().getItem(selectedIndex);
266: if ((pressedReturn)
267: && (tableItem.getData() instanceof ActionInput)) {
268: ;
269: editElement(getTable().getItem(selectedIndex + 1)
270: .getData(), 0);
271: }
272: }
273: }
274: }
275:
276: class InputNameCellEditor extends TextCellEditor {
277: boolean valueChanged = false;
278: boolean pressedReturn = false;
279:
280: public InputNameCellEditor(Composite parent) {
281: super (parent);
282: Text text = (Text) getControl();
283: text.addKeyListener(new KeyListener() {
284:
285: public void keyPressed(KeyEvent e) {
286: e.doit = !Character.isWhitespace(e.character)
287: && (e.character != '-');
288: }
289:
290: public void keyReleased(KeyEvent e) {
291: }
292:
293: });
294: }
295:
296: protected void handleDefaultSelection(SelectionEvent event) {
297: pressedReturn = true;
298: super .handleDefaultSelection(event);
299: }
300:
301: protected void doSetValue(Object value) {
302: if (value instanceof ActionInput) {
303: super .doSetValue(((ActionInput) value).getName());
304: } else {
305: super .doSetValue(value);
306: }
307: valueChanged = false;
308: pressedReturn = false;
309: }
310:
311: public void deactivate() {
312: super .deactivate();
313: if (valueChanged) {
314: valueChanged = false;
315: int selectedIndex = getTable().getSelectionIndex();
316: TableItem tableItem = getTable().getItem(selectedIndex);
317: if ((pressedReturn)
318: && (tableItem.getData() instanceof ActionInput)) {
319: ;
320: editElement(tableItem.getData(), 1);
321: }
322: }
323: }
324: }
325:
326: class InputTypeCellEditor extends CellEditor {
327: boolean valueChanged = false;
328:
329: boolean pressedReturn = false;
330:
331: private String[] items;
332:
333: int selection;
334:
335: CCombo comboBox;
336:
337: private static final int defaultStyle = SWT.NONE;
338:
339: public InputTypeCellEditor(Composite parent) {
340: super (parent, defaultStyle);
341: setItems(ActionSequenceDocument.IO_TYPES);
342: }
343:
344: public String[] getItems() {
345: return this .items;
346: }
347:
348: public void setItems(String[] items) {
349: Assert.isNotNull(items);
350: this .items = items;
351: populateComboBoxItems();
352: }
353:
354: protected Control createControl(Composite parent) {
355:
356: comboBox = new CCombo(parent, getStyle());
357: comboBox.setFont(parent.getFont());
358:
359: comboBox.addKeyListener(new KeyAdapter() {
360: // hook key pressed - see PR 14201
361: public void keyPressed(KeyEvent e) {
362: keyReleaseOccured(e);
363: }
364: });
365:
366: comboBox.addSelectionListener(new SelectionAdapter() {
367: public void widgetDefaultSelected(SelectionEvent event) {
368: pressedReturn = true;
369: applyEditorValueAndDeactivate();
370: }
371:
372: public void widgetSelected(SelectionEvent event) {
373: selection = comboBox.getSelectionIndex();
374: }
375: });
376:
377: comboBox.addTraverseListener(new TraverseListener() {
378: public void keyTraversed(TraverseEvent e) {
379: if (e.detail == SWT.TRAVERSE_ESCAPE
380: || e.detail == SWT.TRAVERSE_RETURN) {
381: e.doit = false;
382: }
383: }
384: });
385:
386: comboBox.addFocusListener(new FocusAdapter() {
387: public void focusLost(FocusEvent e) {
388: InputTypeCellEditor.this .focusLost();
389: }
390: });
391: return comboBox;
392: }
393:
394: /* (non-Javadoc)
395: * @see org.eclipse.jface.viewers.CellEditor#doGetValue()
396: */
397: protected Object doGetValue() {
398: Object value = null;
399: CCombo combo = (CCombo) getControl();
400: int selectedIdx = combo.getSelectionIndex();
401: if (selectedIdx >= 0) {
402: value = combo.getItem(selectedIdx);
403: }
404: return value;
405: }
406:
407: protected void doSetFocus() {
408: comboBox.setFocus();
409: }
410:
411: public LayoutData getLayoutData() {
412: LayoutData layoutData = super .getLayoutData();
413: if ((comboBox == null) || comboBox.isDisposed())
414: layoutData.minimumWidth = 60;
415: else {
416: // make the comboBox 10 characters wide
417: GC gc = new GC(comboBox);
418: layoutData.minimumWidth = (gc.getFontMetrics()
419: .getAverageCharWidth() * 10) + 10;
420: gc.dispose();
421: }
422: return layoutData;
423: }
424:
425: protected void doSetValue(Object value) {
426: valueChanged = false;
427: pressedReturn = false;
428: String typeStr = null;
429: if (value instanceof AbstractIOElement) {
430: AbstractIOElement ioElement = (AbstractIOElement) value;
431: typeStr = ioElement.getType();
432: }
433:
434: ((CCombo) getControl()).setText(typeStr != null ? typeStr
435: : ""); //$NON-NLS-1$
436: }
437:
438: private void populateComboBoxItems() {
439: if (comboBox != null && items != null) {
440: comboBox.removeAll();
441: for (int i = 0; i < items.length; i++)
442: comboBox.add(items[i], i);
443:
444: setValueValid(true);
445: selection = 0;
446: }
447: }
448:
449: void applyEditorValueAndDeactivate() {
450: selection = comboBox.getSelectionIndex();
451: Object newValue = doGetValue();
452: markDirty();
453: boolean isValid = isCorrect(newValue);
454: setValueValid(isValid);
455: if (!isValid) {
456: // try to insert the current value into the error message.
457: setErrorMessage(MessageFormat.format(getErrorMessage(),
458: new Object[] { items[selection] }));
459: }
460: fireApplyEditorValue();
461: deactivate();
462: }
463:
464: protected void focusLost() {
465: if (isActivated()) {
466: applyEditorValueAndDeactivate();
467: }
468: }
469:
470: protected void keyReleaseOccured(KeyEvent keyEvent) {
471: if (keyEvent.character == '\u001b') { // Escape character
472: fireCancelEditor();
473: } else if (keyEvent.character == '\t') { // tab key
474: applyEditorValueAndDeactivate();
475: }
476: }
477:
478: public void deactivate() {
479: // TODO Auto-generated method stub
480: super .deactivate();
481: if (valueChanged) {
482: valueChanged = false;
483: int selectedIndex = getTable().getSelectionIndex();
484: TableItem tableItem = getTable().getItem(selectedIndex);
485: if ((pressedReturn)
486: && (tableItem.getData() instanceof ActionInput)) {
487: ;
488: editElement(tableItem.getData(), 2);
489: }
490: }
491: }
492: }
493:
494: class LabelProvider implements ITableLabelProvider {
495:
496: List listeners = new ArrayList();
497:
498: public LabelProvider() {
499: super ();
500: }
501:
502: public Image getColumnImage(Object element, int columnIndex) {
503: return null;
504: }
505:
506: public String getColumnText(Object element, int columnIndex) {
507: String columnText = ""; //$NON-NLS-1$
508: if (element == ActionUtil.NEW_IO_PLACEHOLDER) {
509: if (columnIndex == NAME_COLUMN_IDX) {
510: columnText = element.toString();
511: }
512: } else if (element instanceof AbstractActionIOElement) {
513: AbstractActionIOElement inputElement = (AbstractActionIOElement) element;
514: switch (columnIndex) {
515: case NAME_COLUMN_IDX:
516: columnText = inputElement.getName();
517: break;
518: case TYPE_COLUMN_IDX:
519: columnText = inputElement.getType();
520: break;
521: case MAPPING_COLUMN_IDX:
522: String mapToName = inputElement.getMapping();
523: if (mapToName.trim().length() != 0) {
524: columnText = ActionUtil
525: .parameterToDisplayText(mapToName);
526: }
527: break;
528: }
529: }
530: return columnText;
531: }
532:
533: public void addListener(ILabelProviderListener listener) {
534: listeners.add(listener);
535: }
536:
537: public void dispose() {
538: }
539:
540: public boolean isLabelProperty(Object element, String property) {
541: return true;
542: }
543:
544: public void removeListener(ILabelProviderListener listener) {
545: listeners.add(listener);
546: }
547:
548: }
549:
550: class InputModifier implements ICellModifier {
551:
552: public boolean canModify(Object element, String property) {
553: return (element instanceof ActionInput)
554: || property.equals(NAME_COLUMN_PROP);
555: }
556:
557: public Object getValue(Object tableObject, String property) {
558: Object value = tableObject;
559: if (property.equals(ActionIOTable.NAME_COLUMN_PROP)) {
560: if (tableObject instanceof ActionInput) {
561: value = ((ActionInput) tableObject).getName();
562: } else if (tableObject == ActionUtil.NEW_IO_PLACEHOLDER) {
563: value = ""; //$NON-NLS-1$
564: }
565: }
566: return value;
567: }
568:
569: public void modify(Object tableObject, String property,
570: Object value) {
571: if (value != null) {
572: if (property.equals(MAPPING_COLUMN_PROP)) {
573: TableItem tableItem = (TableItem) tableObject;
574: if (tableItem.getData() instanceof AbstractIOElement) {
575: AbstractActionIOElement io = (AbstractActionIOElement) tableItem
576: .getData();
577: value = ActionUtil
578: .parameterFromDisplayText(value
579: .toString());
580: if (!value.equals("")) { //$NON-NLS-1$
581: io.setMapping(value.toString());
582: } else {
583: io.setMapping(null);
584: }
585: refresh(io);
586: }
587: inputMappingCellEditor.valueChanged = true;
588: } else {
589: TableItem tableItem = (TableItem) tableObject;
590: if (property.equals(ActionIOTable.NAME_COLUMN_PROP)) {
591: String name = ((String) value).trim();
592: if (name.length() == 0) {
593: if (tableItem.getData() instanceof AbstractActionIOElement) {
594: ErrorDialog
595: .openError(
596: getTable().getShell(),
597: Messages
598: .getString("GenericActionInputsTable.INPUT_ERROR"), Messages.getString("GenericActionInputsTable.INVALID_INPUT_NAME"), new Status(IStatus.ERROR, Messages.getString("GenericActionInputsTable.DESIGN_STUDIO"), 0, Messages.getString("GenericActionInputsTable.EMPTY_INPUT_NAME"), null)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
599: }
600: } else if (name.split("\\s+").length != 1) { //$NON-NLS-1$
601: ErrorDialog
602: .openError(
603: getTable().getShell(),
604: Messages
605: .getString("GenericActionInputsTable.INPUT_ERROR"), Messages.getString("GenericActionInputsTable.INVALID_INPUT_NAME"), new Status(IStatus.ERROR, Messages.getString("GenericActionInputsTable.DESIGN_STUDIO"), 0, Messages.getString("GenericActionInputsTable.NO_SPACES_IN_INPUT_NAME"), null)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
606: } else {
607: if (tableItem.getData() instanceof AbstractActionIOElement) {
608: AbstractActionIOElement ioElement = (AbstractActionIOElement) tableItem
609: .getData();
610: ioElement.setName(name);
611: refresh(ioElement);
612: } else if ((name.length() > 0)
613: && (tableItem.getData() == ActionUtil.NEW_IO_PLACEHOLDER)) {
614: addNewIOElement(name);
615: refresh();
616: setSelection(new StructuredSelection(
617: getElementAt(getTable()
618: .getItemCount() - 2)));
619: }
620: inputNameCellEditor.valueChanged = true;
621: }
622: } else if (property
623: .equals(ActionIOTable.TYPE_COLUMN_PROP)) {
624: if (tableItem.getData() instanceof AbstractActionIOElement) {
625: AbstractActionIOElement ioElement = (AbstractActionIOElement) tableItem
626: .getData();
627: if (Arrays.asList(
628: ActionSequenceDocument.IO_TYPES)
629: .contains(value)) {
630: ioElement.setType(value.toString());
631: refresh(ioElement);
632: }
633: }
634: inputTypeCellEditor.valueChanged = true;
635: }
636: }
637: }
638: }
639: }
640:
641: /**
642: * Creates an ActionInputsViewer
643: * @param parent the parent of this viewer.
644: * @param toolkit the form toolkit.
645: */
646: public GenericActionInputsTable(Composite parent) {
647: super (parent);
648: }
649:
650: /* (non-Javadoc)
651: * @see org.pentaho.designstudio.editors.actionsequence.pages.actions.ActionIOViewer#createContentProvider()
652: */
653: protected IContentProvider createContentProvider() {
654: return new ActionIOContentProvider(true);
655: }
656:
657: /* (non-Javadoc)
658: * @see org.pentaho.designstudio.editors.actionsequence.pages.actions.ActionIOViewer#createLabelProvider()
659: */
660: protected void createLabelProvider() {
661: setLabelProvider(new LabelProvider());
662: }
663:
664: /* (non-Javadoc)
665: * @see org.pentaho.designstudio.editors.actionsequence.pages.actions.ActionIOViewer#createCellEditors()
666: */
667: protected void createCellEditors() {
668: Table table = getTable();
669: inputMappingCellEditor = new InputMappingCellEditor(table);
670: inputNameCellEditor = new InputNameCellEditor(table);
671: inputTypeCellEditor = new InputTypeCellEditor(table);
672: CellEditor[] editors = new CellEditor[] { inputNameCellEditor,
673: inputTypeCellEditor, inputMappingCellEditor };
674: setCellEditors(editors);
675: setCellModifier(new InputModifier());
676: setColumnProperties(new String[] { NAME_COLUMN_PROP,
677: TYPE_COLUMN_PROP, MAPPING_COLUMN_PROP });
678:
679: }
680:
681: /* (non-Javadoc)
682: * @see org.pentaho.designstudio.editors.actionsequence.pages.actions.ActionIOViewer#createTableColumns()
683: */
684: protected void createTableColumns() {
685: super .createTableColumns();
686: TableColumn tableColumn = new TableColumn(getTable(), SWT.LEFT);
687: tableColumn.setText(Messages
688: .getString("ActionInputsTable.UI_MAP_TO_HEADER")); //$NON-NLS-1$
689: tableColumn.pack();
690: }
691:
692: protected void addNewIOElement(String variableName) {
693: actionDefinition.addInputParam(variableName,
694: ActionSequenceDocument.STRING_TYPE);
695: refresh();
696: }
697:
698: }
|