Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: c592b5f90f79e137336627dbff711b7951b45dc3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.debug.internal.ui.viewers;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;

/**
 * This class is copied from package org.eclipse.jface.viewers.TableEditorImpl
 * because the original has package access only.
 * 
 * TODO: complain to UI about package access to API class.
 * 
 */
public abstract class TableEditorImpl {
	private CellEditor fCellEditor;
	private CellEditor[] fCellEditors;
	private ICellModifier fCellModifier;
	private String[] fColumnProperties;
	private Item fTableItem;
	private int fColumnNumber;
	private ICellEditorListener fCellEditorListener;
	private FocusListener fFocusListener;
	private MouseListener fMouseListener;
	private int fDoubleClickExpirationTime;
	private StructuredViewer fViewer;

	TableEditorImpl(StructuredViewer viewer) {
		fViewer = viewer;
		initCellEditorListener();
	}

	/**
	 * Returns this <code>TableViewerImpl</code> viewer
	 * 
	 * @return the viewer
	 */
	public StructuredViewer getViewer() {
		return fViewer;
	}

	private void activateCellEditor() {
		if (fCellEditors != null) {
			if (fCellEditors[fColumnNumber] != null && fCellModifier != null) {
				Object element = fTableItem.getData();
				String property = fColumnProperties[fColumnNumber];
				if (fCellModifier.canModify(element, property)) {
					fCellEditor = fCellEditors[fColumnNumber];
					// table.showSelection();
					fCellEditor.addListener(fCellEditorListener);
					Object value = fCellModifier.getValue(element, property);
					fCellEditor.setValue(value);
					// Tricky flow of control here:
					// activate() can trigger callback to cellEditorListener
					// which will clear cellEditor
					// so must get control first, but must still call activate()
					// even if there is no control.
					final Control control = fCellEditor.getControl();
					fCellEditor.activate();
					if (control == null)
						return;
					setLayoutData(fCellEditor.getLayoutData());
					setEditor(control, fTableItem, fColumnNumber);
					fCellEditor.setFocus();
					if (fFocusListener == null) {
						fFocusListener = new FocusAdapter() {
							@Override
							public void focusLost(FocusEvent e) {
								applyEditorValue();
							}
						};
					}
					control.addFocusListener(fFocusListener);
					fMouseListener = new MouseAdapter() {
						@Override
						public void mouseDown(MouseEvent e) {
							// time wrap?
							// check for expiration of doubleClickTime
							if (e.time <= fDoubleClickExpirationTime) {
								control.removeMouseListener(fMouseListener);
								cancelEditing();
								handleDoubleClickEvent();
							} else if (fMouseListener != null) {
								control.removeMouseListener(fMouseListener);
							}
						}
					};
					control.addMouseListener(fMouseListener);
				}
			}
		}
	}

	/**
	 * Activate a cell editor for the given mouse position.
	 */
	private void activateCellEditor(MouseEvent event) {
		if (fTableItem == null || fTableItem.isDisposed()) {
			// item no longer exists
			return;
		}
		int columnToEdit;
		int columns = getColumnCount();
		if (columns == 0) {
			// If no TableColumn, Table acts as if it has a single column
			// which takes the whole width.
			columnToEdit = 0;
		} else {
			columnToEdit = -1;
			for (int i = 0; i < columns; i++) {
				Rectangle bounds = getBounds(fTableItem, i);
				if (bounds.contains(event.x, event.y)) {
					columnToEdit = i;
					break;
				}
			}
			if (columnToEdit == -1) {
				return;
			}
		}

		fColumnNumber = columnToEdit;
		activateCellEditor();
	}

	/**
	 * Deactivates the currently active cell editor.
	 */
	public void applyEditorValue() {
		CellEditor c = fCellEditor;
		if (c != null) {
			// null out cell editor before calling save
			// in case save results in applyEditorValue being re-entered
			// see 1GAHI8Z: ITPUI:ALL - How to code event notification when
			// using cell editor ?
			fCellEditor = null;
			Item t = fTableItem;
			// don't null out table item -- same item is still selected
			if (t != null && !t.isDisposed()) {
				saveEditorValue(c, t);
			}
			setEditor(null, null, 0);
			c.removeListener(fCellEditorListener);
			Control control = c.getControl();
			if (control != null) {
				if (fMouseListener != null) {
					control.removeMouseListener(fMouseListener);
				}
				if (fFocusListener != null) {
					control.removeFocusListener(fFocusListener);
				}
			}
			c.deactivate();
		}
	}

	/**
	 * Cancels the active cell editor, without saving the value back to the
	 * domain model.
	 */
	public void cancelEditing() {
		if (fCellEditor != null) {
			setEditor(null, null, 0);
			fCellEditor.removeListener(fCellEditorListener);
			CellEditor oldEditor = fCellEditor;
			fCellEditor = null;
			oldEditor.deactivate();
		}
	}

	/**
	 * Start editing the given element.
	 * 
	 * @param element
	 * @param column
	 */
	public void editElement(Object element, int column) {
		if (fCellEditor != null)
			applyEditorValue();

		setSelection(new StructuredSelection(element), true);
		Item[] selection = getSelection();
		if (selection.length != 1)
			return;

		fTableItem = selection[0];

		// Make sure selection is visible
		showSelection();
		fColumnNumber = column;
		activateCellEditor();

	}

	abstract Rectangle getBounds(Item item, int columnNumber);

	/**
	 * Return the array of CellEditors used in the viewer
	 * 
	 * @return the cell editors
	 */
	public CellEditor[] getCellEditors() {
		return fCellEditors;
	}

	/**
	 * Get the cell modifier
	 * 
	 * @return the cell modifier
	 */
	public ICellModifier getCellModifier() {
		return fCellModifier;
	}

	abstract int getColumnCount();

	/**
	 * Return the properties for the column
	 * 
	 * @return the array of column properties
	 */
	public Object[] getColumnProperties() {
		return fColumnProperties;
	}

	abstract Item[] getSelection();

	/**
	 * Handles the mouse down event; activates the cell editor.
	 * 
	 * @param event
	 *            the mouse event that should be handled
	 */
	public void handleMouseDown(MouseEvent event) {
		if (event.button != 1)
			return;

		if (fCellEditor != null)
			applyEditorValue();

		// activate the cell editor immediately. If a second mouseDown
		// is received prior to the expiration of the doubleClick time then
		// the cell editor will be deactivated and a doubleClick event will
		// be processed.
		//
		fDoubleClickExpirationTime = event.time + Display.getCurrent().getDoubleClickTime();

		Item[] items = getSelection();
		// Do not edit if more than one row is selected.
		if (items.length != 1) {
			fTableItem = null;
			return;
		}
		fTableItem = items[0];
		activateCellEditor(event);
	}

	private void initCellEditorListener() {
		fCellEditorListener = new ICellEditorListener() {
			@Override
			public void editorValueChanged(boolean oldValidState, boolean newValidState) {
				// Ignore.
			}

			@Override
			public void cancelEditor() {
				TableEditorImpl.this.cancelEditing();
			}

			@Override
			public void applyEditorValue() {
				TableEditorImpl.this.applyEditorValue();
			}
		};
	}

	/**
	 * Return whether there is an active cell editor.
	 * 
	 * @return <code>true</code> if there is an active cell editor; otherwise
	 *         <code>false</code> is returned.
	 */
	public boolean isCellEditorActive() {
		return fCellEditor != null;
	}

	/**
	 * Saves the value of the currently active cell editor, by delegating to the
	 * cell modifier.
	 */
	private void saveEditorValue(CellEditor cellEditor, Item tableItem) {
		if (fCellModifier != null) {
			if (!cellEditor.isValueValid()) {
				// /Do what ???
			}
			String property = null;
			if (fColumnProperties != null && fColumnNumber < fColumnProperties.length)
				property = fColumnProperties[fColumnNumber];
			fCellModifier.modify(tableItem, property, cellEditor.getValue());
		}
	}

	/**
	 * Set the cell editors
	 * 
	 * @param editors
	 */
	public void setCellEditors(CellEditor[] editors) {
		fCellEditors = editors;
	}

	/**
	 * Set the cell modifier
	 * 
	 * @param modifier
	 */
	public void setCellModifier(ICellModifier modifier) {
		fCellModifier = modifier;
	}

	/**
	 * Set the column properties
	 * 
	 * @param columnProperties
	 */
	public void setColumnProperties(String[] columnProperties) {
		fColumnProperties = columnProperties;
	}

	abstract void setEditor(Control w, Item item, int fColumnNumber);

	abstract void setLayoutData(CellEditor.LayoutData layoutData);

	abstract void setSelection(StructuredSelection selection, boolean b);

	abstract void showSelection();

	abstract void handleDoubleClickEvent();
}

Back to the top