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.Iterator;
019: import java.util.List;
020:
021: import org.eclipse.core.runtime.IStatus;
022: import org.eclipse.core.runtime.Status;
023: import org.eclipse.jface.action.Action;
024: import org.eclipse.jface.action.IMenuListener;
025: import org.eclipse.jface.action.IMenuManager;
026: import org.eclipse.jface.action.MenuManager;
027: import org.eclipse.jface.dialogs.ErrorDialog;
028: import org.eclipse.jface.util.Assert;
029: import org.eclipse.jface.viewers.CellEditor;
030: import org.eclipse.jface.viewers.ICellModifier;
031: import org.eclipse.jface.viewers.ILabelProviderListener;
032: import org.eclipse.jface.viewers.IStructuredContentProvider;
033: import org.eclipse.jface.viewers.IStructuredSelection;
034: import org.eclipse.jface.viewers.ITableLabelProvider;
035: import org.eclipse.jface.viewers.TableViewer;
036: import org.eclipse.jface.viewers.TextCellEditor;
037: import org.eclipse.jface.viewers.Viewer;
038: import org.eclipse.swt.SWT;
039: import org.eclipse.swt.custom.CCombo;
040: import org.eclipse.swt.events.FocusAdapter;
041: import org.eclipse.swt.events.FocusEvent;
042: import org.eclipse.swt.events.KeyAdapter;
043: import org.eclipse.swt.events.KeyEvent;
044: import org.eclipse.swt.events.KeyListener;
045: import org.eclipse.swt.events.SelectionAdapter;
046: import org.eclipse.swt.events.SelectionEvent;
047: import org.eclipse.swt.events.TraverseEvent;
048: import org.eclipse.swt.events.TraverseListener;
049: import org.eclipse.swt.graphics.GC;
050: import org.eclipse.swt.graphics.Image;
051: import org.eclipse.swt.widgets.Composite;
052: import org.eclipse.swt.widgets.Control;
053: import org.eclipse.swt.widgets.Menu;
054: import org.eclipse.swt.widgets.Table;
055: import org.eclipse.swt.widgets.TableColumn;
056: import org.eclipse.swt.widgets.TableItem;
057: import org.eclipse.swt.widgets.Text;
058: import org.pentaho.actionsequence.dom.ActionInput;
059: import org.pentaho.actionsequence.dom.ActionSequenceDocument;
060: import org.pentaho.actionsequence.dom.IActionInputVariable;
061: import org.pentaho.actionsequence.dom.actions.ActionDefinition;
062: import org.pentaho.designstudio.messages.Messages;
063:
064: /**
065: * Table viewer used for viewing and modifying the inputs of an action
066: * definition element.
067: *
068: * @author Angelo Rodriguez
069: */
070: public class TemplateMsgInputsTable extends TableViewer implements
071: IStructuredContentProvider {
072:
073: class DeleteInputAction extends Action {
074: public DeleteInputAction() {
075: super (
076: Messages
077: .getString("GenericActionResourcesTable.DELETE_MENU_ITEM")); //$NON-NLS-1$
078: }
079:
080: public void run() {
081: removeSelectedInput();
082: }
083: }
084:
085: static final int NAME_COLUMN_IDX = 0;
086: static final String NAME_COLUMN_HDR = Messages
087: .getString("TemplateMsgInputsTable.TEMPLATE_PARAMETER_COLUMN_TITLE"); //$NON-NLS-1$
088: static final String NAME_COLUMN_PROP = "NAME"; //$NON-NLS-1$
089: static final String MAPPING_COLUMN_PROP = "MAPPING"; //$NON-NLS-1$
090: static final String MAPPING_COLUMN_HDR = Messages
091: .getString("TemplateMsgInputsTable.USE_VALUE_COLUMN_TITLE"); //$NON-NLS-1$
092: static final int MAPPING_COLUMN_IDX = 1;
093:
094: ActionDefinition actionDefinition;
095: DeleteInputAction deleteInputAction = new DeleteInputAction();
096: InputNameCellEditor inputNameCellEditor;
097: InputMappingCellEditor inputMappingCellEditor;
098:
099: class InputMappingCellEditor extends CellEditor {
100: boolean valueChanged = false;
101: boolean pressedReturn = false;
102: private String[] items;
103: int selection;
104: CCombo comboBox;
105: private static final int defaultStyle = SWT.NONE;
106:
107: public InputMappingCellEditor(Composite parent) {
108: super (parent, defaultStyle);
109: }
110:
111: public String[] getItems() {
112: return this .items;
113: }
114:
115: public void setItems(String[] items) {
116: Assert.isNotNull(items);
117: this .items = items;
118: populateComboBoxItems();
119: }
120:
121: protected Control createControl(Composite parent) {
122:
123: comboBox = new CCombo(parent, getStyle());
124: comboBox.setFont(parent.getFont());
125:
126: comboBox.addKeyListener(new KeyAdapter() {
127: // hook key pressed - see PR 14201
128: public void keyPressed(KeyEvent e) {
129: keyReleaseOccured(e);
130: }
131: });
132:
133: comboBox.addSelectionListener(new SelectionAdapter() {
134: public void widgetDefaultSelected(SelectionEvent event) {
135: pressedReturn = true;
136: applyEditorValueAndDeactivate();
137: }
138:
139: public void widgetSelected(SelectionEvent event) {
140: selection = comboBox.getSelectionIndex();
141: }
142: });
143:
144: comboBox.addTraverseListener(new TraverseListener() {
145: public void keyTraversed(TraverseEvent e) {
146: if (e.detail == SWT.TRAVERSE_ESCAPE
147: || e.detail == SWT.TRAVERSE_RETURN) {
148: e.doit = false;
149: }
150: }
151: });
152:
153: comboBox.addFocusListener(new FocusAdapter() {
154: public void focusLost(FocusEvent e) {
155: InputMappingCellEditor.this .focusLost();
156: }
157: });
158: return comboBox;
159: }
160:
161: /* (non-Javadoc)
162: * @see org.eclipse.jface.viewers.CellEditor#doGetValue()
163: */
164: protected Object doGetValue() {
165: Object value = null;
166: CCombo combo = (CCombo) getControl();
167: int selectedIdx = combo.getSelectionIndex();
168: if (selectedIdx >= 0) {
169: value = combo.getItem(selectedIdx);
170: }
171: return value;
172: }
173:
174: protected void doSetFocus() {
175: comboBox.setFocus();
176: }
177:
178: public LayoutData getLayoutData() {
179: LayoutData layoutData = super .getLayoutData();
180: if ((comboBox == null) || comboBox.isDisposed())
181: layoutData.minimumWidth = 60;
182: else {
183: // make the comboBox 10 characters wide
184: GC gc = new GC(comboBox);
185: layoutData.minimumWidth = (gc.getFontMetrics()
186: .getAverageCharWidth() * 10) + 10;
187: gc.dispose();
188: }
189: return layoutData;
190: }
191:
192: private void setAvailComboOptions() {
193: setItems(new String[0]);
194: ArrayList items = new ArrayList();
195: if (actionDefinition != null) {
196: IActionInputVariable[] availInputs = actionDefinition
197: .getAvailInputVariables(ActionSequenceDocument.STRING_TYPE);
198: for (int i = 0; i < availInputs.length; i++) {
199: items.add(ActionUtil
200: .parameterToDisplayText(availInputs[i]
201: .getVariableName()));
202: }
203: items.add(0, ""); //$NON-NLS-1$
204: }
205: setItems((String[]) items.toArray(new String[0]));
206: }
207:
208: protected void doSetValue(Object value) {
209: valueChanged = false;
210: pressedReturn = false;
211:
212: setAvailComboOptions();
213:
214: String mapToName = ""; //$NON-NLS-1$
215: if (value instanceof ActionInput) {
216: ActionInput inputElement = (ActionInput) value;
217: mapToName = inputElement.getMapping();
218: if (mapToName.trim().length() != 0) {
219: mapToName = ActionUtil
220: .parameterToDisplayText(mapToName);
221: }
222: }
223:
224: CCombo combo = (CCombo) getControl();
225: combo.setText(mapToName);
226: }
227:
228: private void populateComboBoxItems() {
229: if (comboBox != null && items != null) {
230: comboBox.removeAll();
231: for (int i = 0; i < items.length; i++)
232: comboBox.add(items[i], i);
233:
234: setValueValid(true);
235: selection = 0;
236: }
237: }
238:
239: void applyEditorValueAndDeactivate() {
240: selection = comboBox.getSelectionIndex();
241: Object newValue = doGetValue();
242: markDirty();
243: boolean isValid = isCorrect(newValue);
244: setValueValid(isValid);
245: if (!isValid) {
246: // try to insert the current value into the error message.
247: setErrorMessage(MessageFormat.format(getErrorMessage(),
248: new Object[] { items[selection] }));
249: }
250: fireApplyEditorValue();
251: deactivate();
252: }
253:
254: protected void focusLost() {
255: if (isActivated()) {
256: applyEditorValueAndDeactivate();
257: }
258: }
259:
260: protected void keyReleaseOccured(KeyEvent keyEvent) {
261: if (keyEvent.character == '\u001b') { // Escape character
262: fireCancelEditor();
263: } else if (keyEvent.character == '\t') { // tab key
264: applyEditorValueAndDeactivate();
265: }
266: }
267:
268: public void deactivate() {
269: super .deactivate();
270: if (valueChanged) {
271: valueChanged = false;
272: int selectedIndex = getTable().getSelectionIndex();
273: TableItem tableItem = getTable().getItem(selectedIndex);
274: if ((pressedReturn)
275: && (tableItem.getData() instanceof ActionInput)) {
276: ;
277: editElement(getTable().getItem(selectedIndex + 1)
278: .getData(), 0);
279: }
280: }
281: }
282: }
283:
284: class InputNameCellEditor extends TextCellEditor {
285: boolean valueChanged = false;
286: boolean pressedReturn = false;
287:
288: public InputNameCellEditor(Composite parent) {
289: super (parent);
290: Text text = (Text) getControl();
291: text.addKeyListener(new KeyListener() {
292:
293: public void keyPressed(KeyEvent e) {
294: e.doit = !Character.isWhitespace(e.character)
295: && (e.character != '-');
296: }
297:
298: public void keyReleased(KeyEvent e) {
299: }
300:
301: });
302: }
303:
304: protected void handleDefaultSelection(SelectionEvent event) {
305: pressedReturn = true;
306: super .handleDefaultSelection(event);
307: }
308:
309: protected void doSetValue(Object value) {
310: if (value instanceof ActionInput) {
311: super .doSetValue(((ActionInput) value).getName());
312: } else {
313: super .doSetValue(value);
314: }
315: valueChanged = false;
316: pressedReturn = false;
317: }
318:
319: public void deactivate() {
320: super .deactivate();
321: if (valueChanged) {
322: valueChanged = false;
323: int selectedIndex = getTable().getSelectionIndex();
324: TableItem tableItem = getTable().getItem(selectedIndex);
325: if ((pressedReturn)
326: && (tableItem.getData() instanceof ActionInput)) {
327: ;
328: editElement(tableItem.getData(), 1);
329: }
330: }
331: }
332: }
333:
334: class LabelProvider implements ITableLabelProvider {
335:
336: List listeners = new ArrayList();
337:
338: public LabelProvider() {
339: super ();
340: }
341:
342: public Image getColumnImage(Object element, int columnIndex) {
343: return null;
344: }
345:
346: public String getColumnText(Object element, int columnIndex) {
347: String columnText = ""; //$NON-NLS-1$
348: if (element instanceof ActionInput) {
349: ActionInput inputElement = (ActionInput) element;
350: switch (columnIndex) {
351: case NAME_COLUMN_IDX:
352: columnText = inputElement.getName();
353: break;
354: case MAPPING_COLUMN_IDX:
355: String mapToName = inputElement.getMapping();
356: if (mapToName.trim().length() != 0) {
357: columnText = ActionUtil
358: .parameterToDisplayText(mapToName);
359: }
360: break;
361: }
362: }
363: return columnText;
364: }
365:
366: public void addListener(ILabelProviderListener listener) {
367: listeners.add(listener);
368: }
369:
370: public void dispose() {
371: }
372:
373: public boolean isLabelProperty(Object element, String property) {
374: return true;
375: }
376:
377: public void removeListener(ILabelProviderListener listener) {
378: listeners.add(listener);
379: }
380:
381: }
382:
383: class InputModifier implements ICellModifier {
384:
385: public boolean canModify(Object element, String property) {
386: return (element instanceof ActionInput)
387: || property.equals(NAME_COLUMN_PROP);
388: }
389:
390: public Object getValue(Object tableObject, String property) {
391: Object value = tableObject;
392: if (tableObject instanceof ActionInput) {
393: ActionInput actionInput = (ActionInput) tableObject;
394: if (property.equals(ActionIOTable.NAME_COLUMN_PROP)) {
395: value = actionInput.getName();
396: } else if (property.equals(MAPPING_COLUMN_PROP)) {
397: if (actionInput.getReferencedVariableName().equals(
398: actionInput.getName())) {
399: value = ""; //$NON-NLS-1$
400: } else {
401: value = actionInput.getReferencedVariableName();
402: }
403: }
404: } else {
405: value = ""; //$NON-NLS-1$
406: }
407: return value;
408: }
409:
410: public void modify(Object tableObject, String property,
411: Object value) {
412: if (value != null) {
413: if (property.equals(MAPPING_COLUMN_PROP)) {
414: TableItem tableItem = (TableItem) tableObject;
415: if (tableItem.getData() instanceof ActionInput) {
416: ActionInput actionInput = (ActionInput) tableItem
417: .getData();
418: value = ActionUtil
419: .parameterFromDisplayText(value
420: .toString());
421: if (!value.equals("")) { //$NON-NLS-1$
422: actionInput.setMapping(value.toString());
423: } else {
424: actionInput.setMapping(null);
425: }
426: refresh(actionInput);
427: }
428: inputMappingCellEditor.valueChanged = true;
429: } else {
430: TableItem tableItem = (TableItem) tableObject;
431: if (property.equals(NAME_COLUMN_PROP)) {
432: String name = ((String) value).trim();
433: if (name.length() == 0) {
434: if (tableItem.getData() instanceof ActionInput) {
435: ErrorDialog
436: .openError(
437: getTable().getShell(),
438: Messages
439: .getString("GenericActionResourcesTable.RESOURCE_ERROR"), Messages.getString("GenericActionResourcesTable.INVALID_RESOURCE_NAME"), new Status(IStatus.ERROR, Messages.getString("GenericActionInputsTable.DESIGN_STUDIO"), 0, Messages.getString("GenericActionResourcesTable.EMPTY_RESOURCE_NAME"), null)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
440: }
441: } else if (name.split("\\s+").length != 1) { //$NON-NLS-1$
442: ErrorDialog
443: .openError(
444: getTable().getShell(),
445: Messages
446: .getString("GenericActionResourcesTable.RESOURCE_ERROR"), Messages.getString("GenericActionResourcesTable.INVALID_RESOURCE_NAME"), new Status(IStatus.ERROR, Messages.getString("GenericActionInputsTable.DESIGN_STUDIO"), 0, Messages.getString("GenericActionResourcesTable.NO_SPACES_IN_RESOURCE_NAME"), null)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
447: } else {
448: if (tableItem.getData() instanceof ActionInput) {
449: ActionInput actionInput = (ActionInput) tableItem
450: .getData();
451: actionDefinition.renameInputParam(
452: actionInput.getName(), name);
453: refresh(actionInput);
454: }
455: inputNameCellEditor.valueChanged = true;
456: }
457: }
458: }
459: }
460: }
461: }
462:
463: /**
464: * Creates an GenericActionResourcesTable
465: * @param parent the parent of this viewer.
466: * @param toolkit the form toolkit.
467: */
468: public TemplateMsgInputsTable(Composite parent) {
469: super (WidgetFactory.createTable(parent, SWT.FULL_SELECTION
470: | SWT.BORDER));
471:
472: Table table = getTable();
473: table.setHeaderVisible(true);
474: createTableColumns();
475: setContentProvider(this );
476: createLabelProvider();
477: createCellEditors();
478: createPopupMenu();
479: }
480:
481: protected void createPopupMenu() {
482: MenuManager popupMenu = new MenuManager();
483: popupMenu.add(deleteInputAction);
484: popupMenu.addMenuListener(new IMenuListener() {
485: public void menuAboutToShow(IMenuManager manager) {
486: updatePopupMenuState(manager);
487: }
488: });
489:
490: Table table = getTable();
491: Menu menu = popupMenu.createContextMenu(table);
492: table.setMenu(menu);
493: }
494:
495: protected void removeSelectedInput() {
496: IStructuredSelection selection = (IStructuredSelection) getSelection();
497: remove(selection.toArray());
498: List selections = selection.toList();
499: for (Iterator iter = selections.iterator(); iter.hasNext();) {
500: ActionInput selectedInput = (ActionInput) iter.next();
501: selectedInput.delete();
502: remove(selectedInput);
503: }
504: }
505:
506: /* (non-Javadoc)
507: * @see org.pentaho.designstudio.editors.actionsequence.pages.actions.ActionIOViewer#createLabelProvider()
508: */
509: protected void createLabelProvider() {
510: setLabelProvider(new LabelProvider());
511: }
512:
513: /* (non-Javadoc)
514: * @see org.pentaho.designstudio.editors.actionsequence.pages.actions.ActionIOViewer#createCellEditors()
515: */
516: protected void createCellEditors() {
517: Table table = getTable();
518: inputMappingCellEditor = new InputMappingCellEditor(table);
519: inputNameCellEditor = new InputNameCellEditor(table);
520: CellEditor[] editors = new CellEditor[] { inputNameCellEditor,
521: inputMappingCellEditor };
522: setCellEditors(editors);
523: setCellModifier(new InputModifier());
524: setColumnProperties(new String[] { NAME_COLUMN_PROP,
525: MAPPING_COLUMN_PROP });
526:
527: }
528:
529: /* (non-Javadoc)
530: * @see org.pentaho.designstudio.editors.actionsequence.pages.actions.ActionIOViewer#createTableColumns()
531: */
532: protected void createTableColumns() {
533: Table table = getTable();
534: TableColumn tableColumn = new TableColumn(table, SWT.LEFT);
535: tableColumn.setText(NAME_COLUMN_HDR);
536: tableColumn.setWidth(200);
537: tableColumn = new TableColumn(getTable(), SWT.LEFT);
538: tableColumn.setText(MAPPING_COLUMN_HDR);
539: tableColumn.pack();
540: }
541:
542: protected void addNewInput(String variableName) {
543: actionDefinition.addInputParam(variableName,
544: ActionSequenceDocument.STRING_TYPE);
545: refresh();
546: }
547:
548: private void updatePopupMenuState(IMenuManager menuMgr) {
549: deleteInputAction.setEnabled(true);
550: }
551:
552: protected void inputChanged(Object input, Object oldInput) {
553: actionDefinition = (ActionDefinition) input;
554: super .inputChanged(input, oldInput);
555: }
556:
557: public Object[] getElements(Object inputElement) {
558: ArrayList elements = new ArrayList();
559: ActionInput[] actionInputs = actionDefinition
560: .getAllInputParams();
561: ArrayList expectedInputs = new ArrayList(Arrays
562: .asList(actionDefinition.getReservedInputNames()));
563: for (int i = 0; i < actionInputs.length; i++) {
564: if (!expectedInputs.contains(actionInputs[i].getName())) {
565: elements.add(actionInputs[i]);
566: }
567: }
568: elements.add(ActionUtil.NEW_IO_PLACEHOLDER);
569: return elements.toArray();
570: }
571:
572: public void dispose() {
573: }
574:
575: public void inputChanged(Viewer viewer, Object oldInput,
576: Object newInput) {
577: }
578: }
|