tmf: Add support for time range selection
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / virtualtable / TmfVirtualTable.java
CommitLineData
9ccc6d01 1/*******************************************************************************
c8422608 2 * Copyright (c) 2010, 2013 Ericsson
3934297e 3 *
9ccc6d01
FC
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
3934297e 8 *
9ccc6d01
FC
9 * Contributors:
10 * Matthew Khouzam - Initial API and implementation
3934297e 11 * Francois Chouinard - Refactoring, slider support, bug fixing
b21305c2 12 * Patrick Tasse - Improvements and bug fixing
7cc11afa 13 * Xavier Raynaud - Improvements
9ccc6d01
FC
14 ******************************************************************************/
15
fb5cad3d 16package org.eclipse.linuxtools.tmf.ui.widgets.virtualtable;
9ccc6d01 17
8fd82db5 18import org.eclipse.linuxtools.internal.tmf.ui.Activator;
9ccc6d01 19import org.eclipse.swt.SWT;
b21305c2 20import org.eclipse.swt.custom.TableEditor;
9ccc6d01
FC
21import org.eclipse.swt.events.ControlAdapter;
22import org.eclipse.swt.events.ControlEvent;
23import org.eclipse.swt.events.KeyEvent;
24import org.eclipse.swt.events.KeyListener;
25import org.eclipse.swt.events.MouseEvent;
b21305c2 26import org.eclipse.swt.events.MouseListener;
9ccc6d01 27import org.eclipse.swt.events.MouseWheelListener;
dd03e2f1
PT
28import org.eclipse.swt.events.PaintEvent;
29import org.eclipse.swt.events.PaintListener;
9ccc6d01
FC
30import org.eclipse.swt.events.SelectionAdapter;
31import org.eclipse.swt.events.SelectionEvent;
b21305c2
FC
32import org.eclipse.swt.events.SelectionListener;
33import org.eclipse.swt.graphics.Point;
7800a42f
XR
34import org.eclipse.swt.graphics.Rectangle;
35import org.eclipse.swt.layout.FillLayout;
9ccc6d01
FC
36import org.eclipse.swt.layout.GridData;
37import org.eclipse.swt.layout.GridLayout;
38import org.eclipse.swt.widgets.Composite;
b21305c2 39import org.eclipse.swt.widgets.Control;
9ccc6d01 40import org.eclipse.swt.widgets.Event;
7800a42f 41import org.eclipse.swt.widgets.Label;
9ccc6d01 42import org.eclipse.swt.widgets.Listener;
b21305c2 43import org.eclipse.swt.widgets.Menu;
7800a42f 44import org.eclipse.swt.widgets.Shell;
9ccc6d01
FC
45import org.eclipse.swt.widgets.Slider;
46import org.eclipse.swt.widgets.Table;
47import org.eclipse.swt.widgets.TableColumn;
48import org.eclipse.swt.widgets.TableItem;
7800a42f 49import org.eclipse.ui.PlatformUI;
9ccc6d01
FC
50
51/**
52 * <b><u>TmfVirtualTable</u></b>
53 * <p>
54 * TmfVirtualTable allows for the tabular display of arbitrarily large data sets
55 * (well, up to Integer.MAX_VALUE or ~2G rows).
3934297e 56 *
9ccc6d01
FC
57 * It is essentially a Composite of Table and Slider, where the number of rows
58 * in the table is set to fill the table display area. The slider is rank-based.
3934297e 59 *
9ccc6d01
FC
60 * It differs from Table with the VIRTUAL style flag where an empty entry is
61 * created for each virtual row. This does not scale well for very large data sets.
3934297e 62 *
b21305c2
FC
63 * Styles:
64 * H_SCROLL, V_SCROLL, SINGLE, CHECK, FULL_SELECTION, HIDE_SELECTION, NO_SCROLL
02023181 65 * @author Matthew Khouzam, Francois Chouinard, Patrick Tasse, Xavier Raynaud
3934297e 66 * @version $Revision: 1.0
9ccc6d01
FC
67 */
68public class TmfVirtualTable extends Composite {
69
631d853f
PT
70 // The table
71 private Table fTable;
72 private int fTableRows = 0; // Number of table rows
73 private int fFullyVisibleRows = 0; // Number of fully visible table rows
74 private int fFrozenRowCount = 0; // Number of frozen table rows at top of table
75
76 private int fTableTopEventRank = 0; // Global rank of the first entry displayed
77 private int fSelectedEventRank = 0; // Global rank of the selected event
78 private boolean fPendingSelection = false; // Pending selection update
79
80 private int fTableItemCount = 0;
81
82 // The slider
83 private Slider fSlider;
84
85 private int fLinuxItemHeight = 0; // Calculated item height for Linux workaround
86 private TooltipProvider tooltipProvider = null;
87 private IDoubleClickListener doubleClickListener = null;
88
b06f64b7
PT
89 private boolean fResetTopIndex = false; // Flag to trigger reset of top index
90 private ControlAdapter fResizeListener; // Resize listener to update visible rows
c9787691 91
631d853f
PT
92 // ------------------------------------------------------------------------
93 // Constructor
94 // ------------------------------------------------------------------------
95
96 /**
3934297e
AM
97 * Standard constructor
98 *
631d853f 99 * @param parent
3934297e 100 * The parent composite object
631d853f 101 * @param style
3934297e 102 * The style to use
631d853f
PT
103 */
104 public TmfVirtualTable(Composite parent, int style) {
105 super(parent, style & (~SWT.H_SCROLL) & (~SWT.V_SCROLL) & (~SWT.SINGLE) & (~SWT.FULL_SELECTION) & (~SWT.HIDE_SELECTION) & (~SWT.CHECK));
106
107 // Create the controls
108 createTable(style & (SWT.H_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION | SWT.HIDE_SELECTION | SWT.CHECK));
109 createSlider(style & SWT.V_SCROLL);
110
111 // Prevent the slider from being traversed
112 setTabList(new Control[] { fTable });
113
114 // Set the layout
115 GridLayout gridLayout = new GridLayout();
116 gridLayout.numColumns = 2;
117 gridLayout.horizontalSpacing = 0;
118 gridLayout.verticalSpacing = 0;
119 gridLayout.marginWidth = 0;
120 gridLayout.marginHeight = 0;
121 setLayout(gridLayout);
122
123 GridData tableGridData = new GridData(SWT.FILL, SWT.FILL, true, true);
124 fTable.setLayoutData(tableGridData);
125
126 GridData sliderGridData = new GridData(SWT.FILL, SWT.FILL, false, true);
127 fSlider.setLayoutData(sliderGridData);
128
129 // Add the listeners
130 fTable.addMouseWheelListener(new MouseWheelListener() {
131 @Override
132 public void mouseScrolled(MouseEvent event) {
133 if (fTableItemCount <= fFullyVisibleRows) {
134 return;
135 }
136 fTableTopEventRank -= event.count;
137 if (fTableTopEventRank < 0) {
138 fTableTopEventRank = 0;
139 }
140 int latestFirstRowOffset = fTableItemCount - fFullyVisibleRows;
141 if (fTableTopEventRank > latestFirstRowOffset) {
142 fTableTopEventRank = latestFirstRowOffset;
143 }
144
145 fSlider.setSelection(fTableTopEventRank);
146 refreshTable();
147 }
148 });
149
150 fTable.addListener(SWT.MouseWheel, new Listener() {
151 // disable mouse scroll of horizontal scroll bar
152 @Override
b21305c2 153 public void handleEvent(Event event) {
631d853f
PT
154 event.doit = false;
155 }
156 });
157
b06f64b7 158 fResizeListener = new ControlAdapter() {
631d853f
PT
159 @Override
160 public void controlResized(ControlEvent event) {
161 int tableHeight = Math.max(0, fTable.getClientArea().height - fTable.getHeaderHeight());
162 fFullyVisibleRows = tableHeight / getItemHeight();
163 if (fTableItemCount > 0) {
164 fSlider.setThumb(Math.max(1, Math.min(fTableRows, fFullyVisibleRows)));
165 }
166 }
b06f64b7
PT
167 };
168 fTable.addControlListener(fResizeListener);
169
631d853f
PT
170 // Implement a "fake" tooltip
171 final String TOOLTIP_DATA_KEY = "_TABLEITEM"; //$NON-NLS-1$
172 final Listener labelListener = new Listener () {
173 @Override
f4c52cea 174 public void handleEvent (Event event) {
631d853f
PT
175 Label label = (Label)event.widget;
176 Shell shell = label.getShell ();
177 switch (event.type) {
178 case SWT.MouseDown:
179 Event e = new Event ();
180 e.item = (TableItem) label.getData (TOOLTIP_DATA_KEY);
181 // Assuming table is single select, set the selection as if
182 // the mouse down event went through to the table
183 fTable.setSelection (new TableItem [] {(TableItem) e.item});
184 fTable.notifyListeners (SWT.Selection, e);
185 shell.dispose ();
186 fTable.setFocus();
187 break;
188 case SWT.MouseExit:
189 case SWT.MouseWheel:
190 shell.dispose ();
191 break;
abbdd66a
AM
192 default:
193 break;
631d853f
PT
194 }
195 }
196 };
197
198 Listener tableListener = new Listener () {
199 Shell tip = null;
200 Label label = null;
201 @Override
f4c52cea 202 public void handleEvent (Event event) {
631d853f
PT
203 switch (event.type) {
204 case SWT.Dispose:
205 case SWT.KeyDown:
206 case SWT.MouseMove: {
420bceb2
PT
207 if (tip == null) {
208 break;
209 }
631d853f
PT
210 tip.dispose ();
211 tip = null;
212 label = null;
213 break;
214 }
215 case SWT.MouseHover: {
216 TableItem item = fTable.getItem (new Point(event.x, event.y));
217 if (item != null) {
420bceb2 218 for (int i=0; i < fTable.getColumnCount(); i++) {
631d853f
PT
219 Rectangle bounds = item.getBounds(i);
220 if (bounds.contains(event.x,event.y)){
420bceb2
PT
221 if (tip != null && !tip.isDisposed()) {
222 tip.dispose();
223 }
631d853f
PT
224 if (tooltipProvider == null) {
225 return;
631d853f 226 }
abbdd66a
AM
227 String tooltipText = tooltipProvider.getTooltip(i, item.getData());
228 if (tooltipText == null) {
229 return;
230 }
231 tip = new Shell(fTable.getShell(), SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
232 tip.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
233 FillLayout layout = new FillLayout();
234 layout.marginWidth = 2;
235 tip.setLayout(layout);
236 label = new Label(tip, SWT.WRAP);
237 label.setForeground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
238 label.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
239 label.setData(TOOLTIP_DATA_KEY, item);
240 label.setText(tooltipText);
241
242 label.addListener(SWT.MouseExit, labelListener);
243 label.addListener(SWT.MouseDown, labelListener);
244 label.addListener(SWT.MouseWheel, labelListener);
245 Point size = tip.computeSize(SWT.DEFAULT, SWT.DEFAULT);
246 Point pt = fTable.toDisplay(bounds.x, bounds.y);
247 tip.setBounds(pt.x, pt.y, size.x, size.y);
248 tip.setVisible(true);
631d853f
PT
249 }
250 }
251 }
abbdd66a 252 break;
631d853f 253 }
abbdd66a
AM
254 default:
255 break;
631d853f
PT
256 }
257 }
258 };
259 fTable.addListener(SWT.Dispose, tableListener);
260 fTable.addListener(SWT.KeyDown, tableListener);
261 fTable.addListener(SWT.MouseMove, tableListener);
262 fTable.addListener(SWT.MouseHover, tableListener);
263 addControlListener(new ControlAdapter() {
264 @Override
265 public void controlResized(ControlEvent event) {
266 resize();
420bceb2
PT
267 if (fTableItemCount > 0) {
268 fSlider.setThumb(Math.max(1, Math.min(fTableRows, fFullyVisibleRows)));
269 }
631d853f
PT
270 }
271 });
272
273 // And display
274 refresh();
275 }
276
277 // ------------------------------------------------------------------------
278 // Table handling
279 // ------------------------------------------------------------------------
280
281 /**
282 * Create the table and add listeners
02023181 283 * @param style int can be H_SCROLL, V_SCROLL, SINGLE, CHECK, FULL_SELECTION, HIDE_SELECTION, NO_SCROLL
631d853f
PT
284 */
285 private void createTable(int style) {
286 fTable = new Table(this, style | SWT.NO_SCROLL);
287
288 fTable.addSelectionListener(new SelectionAdapter() {
289 @Override
290 public void widgetSelected(SelectionEvent event) {
291 if (fTable.getSelectionIndices().length > 0) {
292 handleTableSelection();
293 }
294 }
295 });
9ccc6d01 296
2cc874d6 297 fTable.addKeyListener(new KeyListener() {
631d853f
PT
298 @Override
299 public void keyPressed(KeyEvent event) {
300 handleTableKeyEvent(event);
301 }
302 @Override
303 public void keyReleased(KeyEvent event) {
304 }
305 });
7800a42f
XR
306
307 fTable.addListener(
631d853f
PT
308 SWT.MouseDoubleClick, new Listener() {
309 @Override
310 public void handleEvent(Event event) {
311 if (doubleClickListener != null) {
312 TableItem item = fTable.getItem (new Point (event.x, event.y));
313 if (item != null) {
314 for(int i=0;i<fTable.getColumnCount();i++){
315 Rectangle bounds = item.getBounds(i);
316 if (bounds.contains(event.x,event.y)){
317 doubleClickListener.handleDoubleClick(TmfVirtualTable.this, item, i);
318 break;
319 }
320 }
321 }
322 }
323 }
324 }
325 );
dd03e2f1
PT
326
327 /*
c9787691
PT
328 * Feature in Windows. When a partially visible table item is selected,
329 * after ~500 ms the top index is changed to ensure the selected item is
330 * fully visible. This leaves a blank space at the bottom of the virtual
331 * table. The workaround is to reset the top index to 0 if it is not 0.
332 * Also reset the top index to 0 if indicated by the flag that was set
333 * at table selection of a partially visible table item.
dd03e2f1
PT
334 */
335 fTable.addPaintListener(new PaintListener() {
336 @Override
337 public void paintControl(PaintEvent e) {
c9787691
PT
338 if (fTable.getTopIndex() != 0 || fResetTopIndex) {
339 fTable.setTopIndex(0);
340 }
341 fResetTopIndex = false;
dd03e2f1
PT
342 }
343 });
631d853f
PT
344 }
345
346 /**
347 * Update the rows and selected item
348 */
349 private void handleTableSelection() {
350 int selectedRow = fTable.getSelectionIndices()[0];
351 if (selectedRow < fFrozenRowCount) {
352 fSelectedEventRank = selectedRow;
353 } else {
354 fSelectedEventRank = fTableTopEventRank + selectedRow;
355 }
c9787691
PT
356
357 /*
358 * Feature in Linux. When a partially visible table item is selected,
359 * the origin is changed to ensure the selected item is fully visible.
360 * This makes the first row partially visible. The solution is to force
361 * reset the origin by setting the top index to 0. This should happen
362 * only once at the next redraw by the paint listener.
363 */
364 if (selectedRow >= fFullyVisibleRows) {
365 fResetTopIndex = true;
366 }
631d853f
PT
367 }
368
369 /**
370 * Handle key-based navigation in table.
3934297e 371 *
631d853f
PT
372 * @param event
373 */
374 private void handleTableKeyEvent(KeyEvent event) {
375
376 int lastEventRank = fTableItemCount - 1;
377 int lastPageTopEntryRank = Math.max(0, fTableItemCount - fFullyVisibleRows);
378
379 int previousSelectedEventRank = fSelectedEventRank;
380 int selectedRow = fSelectedEventRank - fTableTopEventRank;
381 boolean needsRefresh = false;
382
383 // In all case, perform the following steps:
384 // - Update the selected entry rank (within valid range)
385 // - Update the selected row
386 // - Update the page's top entry if necessary (which also adjusts the selected row)
387 // - If the top displayed entry was changed, table refresh is needed
388 switch (event.keyCode) {
389
390 case SWT.ARROW_DOWN: {
391 event.doit = false;
392 if (fSelectedEventRank < lastEventRank) {
393 fSelectedEventRank++;
394 selectedRow = fSelectedEventRank - fTableTopEventRank;
75c271cf 395 if (selectedRow == fFullyVisibleRows) {
631d853f
PT
396 fTableTopEventRank++;
397 needsRefresh = true;
75c271cf
PT
398 } else if (selectedRow < fFrozenRowCount || selectedRow > fFullyVisibleRows) {
399 fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
400 needsRefresh = true;
631d853f
PT
401 }
402 }
403 break;
404 }
405
406 case SWT.ARROW_UP: {
407 event.doit = false;
408 if (fSelectedEventRank > 0) {
409 fSelectedEventRank--;
410 selectedRow = fSelectedEventRank - fTableTopEventRank;
75c271cf 411 if (selectedRow == fFrozenRowCount - 1 && fTableTopEventRank > 0) {
631d853f
PT
412 fTableTopEventRank--;
413 needsRefresh = true;
75c271cf
PT
414 } else if (selectedRow < fFrozenRowCount || selectedRow > fFullyVisibleRows) {
415 fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
416 needsRefresh = true;
631d853f
PT
417 }
418 }
419 break;
420 }
421
422 case SWT.END: {
423 event.doit = false;
424 fTableTopEventRank = lastPageTopEntryRank;
425 fSelectedEventRank = lastEventRank;
426 needsRefresh = true;
427 break;
428 }
429
430 case SWT.HOME: {
431 event.doit = false;
432 fSelectedEventRank = fFrozenRowCount;
433 fTableTopEventRank = 0;
434 needsRefresh = true;
435 break;
436 }
437
438 case SWT.PAGE_DOWN: {
439 event.doit = false;
440 if (fSelectedEventRank < lastEventRank) {
441 fSelectedEventRank += fFullyVisibleRows;
442 if (fSelectedEventRank > lastEventRank) {
443 fSelectedEventRank = lastEventRank;
444 }
445 selectedRow = fSelectedEventRank - fTableTopEventRank;
75c271cf 446 if (selectedRow > fFullyVisibleRows + fFrozenRowCount - 1 && selectedRow < 2 * fFullyVisibleRows) {
631d853f
PT
447 fTableTopEventRank += fFullyVisibleRows;
448 if (fTableTopEventRank > lastPageTopEntryRank) {
449 fTableTopEventRank = lastPageTopEntryRank;
450 }
451 needsRefresh = true;
75c271cf
PT
452 } else if (selectedRow < fFrozenRowCount || selectedRow >= 2 * fFullyVisibleRows) {
453 fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
454 needsRefresh = true;
631d853f
PT
455 }
456 }
457 break;
458 }
459
460 case SWT.PAGE_UP: {
461 event.doit = false;
462 if (fSelectedEventRank > 0) {
463 fSelectedEventRank -= fFullyVisibleRows;
464 if (fSelectedEventRank < fFrozenRowCount) {
465 fSelectedEventRank = fFrozenRowCount;
466 }
467 selectedRow = fSelectedEventRank - fTableTopEventRank;
75c271cf 468 if (selectedRow < fFrozenRowCount && selectedRow > -fFullyVisibleRows) {
631d853f
PT
469 fTableTopEventRank -= fFullyVisibleRows;
470 if (fTableTopEventRank < 0) {
471 fTableTopEventRank = 0;
472 }
473 needsRefresh = true;
75c271cf
PT
474 } else if (selectedRow <= -fFullyVisibleRows || selectedRow >= fFullyVisibleRows) {
475 fTableTopEventRank = Math.max(0, Math.min(fSelectedEventRank - fFrozenRowCount, lastPageTopEntryRank));
476 needsRefresh = true;
631d853f
PT
477 }
478 }
479 break;
480 }
481 default: {
482 return;
483 }
484 }
485
486 boolean done = true;
487 if (needsRefresh) {
488 done = refreshTable(); // false if table items not updated yet in this thread
489 } else {
490 fTable.select(selectedRow);
491 }
492
493 if (fFullyVisibleRows < fTableItemCount) {
494 fSlider.setSelection(fTableTopEventRank);
495 }
496
420bceb2 497 if (fSelectedEventRank != previousSelectedEventRank && fSelectedEventRank < fTableItemCount) {
631d853f
PT
498 if (done) {
499 Event e = new Event();
500 e.item = fTable.getSelection()[0];
501 fTable.notifyListeners(SWT.Selection, e);
502 } else {
503 fPendingSelection = true;
504 }
505 }
506 }
507
02023181
MK
508 /**
509 * Method setDataItem.
510 * @param index int
511 * @param item TableItem
512 * @return boolean
513 */
631d853f
PT
514 private boolean setDataItem(int index, TableItem item) {
515 if (index != -1) {
516 Event event = new Event();
517 event.item = item;
518 if (index < fFrozenRowCount) {
519 event.index = index;
520 } else {
521 event.index = index + fTableTopEventRank;
522 }
523 event.doit = true;
524 fTable.notifyListeners(SWT.SetData, event);
525 return event.doit; // false if table item not updated yet in this thread
526 }
527 return true;
528 }
529
530 // ------------------------------------------------------------------------
531 // Slider handling
532 // ------------------------------------------------------------------------
533
02023181
MK
534 /**
535 * Method createSlider.
536 * @param style int
537 */
631d853f
PT
538 private void createSlider(int style) {
539 fSlider = new Slider(this, SWT.VERTICAL | SWT.NO_FOCUS);
540 fSlider.setMinimum(0);
541 fSlider.setMaximum(0);
542 if ((style & SWT.V_SCROLL) == 0) {
543 fSlider.setVisible(false);
544 }
545
546 fSlider.addListener(SWT.Selection, new Listener() {
547 @Override
548 public void handleEvent(Event event) {
549 switch (event.detail) {
550 case SWT.ARROW_DOWN:
551 case SWT.ARROW_UP:
552 case SWT.NONE:
553 case SWT.END:
554 case SWT.HOME:
555 case SWT.PAGE_DOWN:
556 case SWT.PAGE_UP: {
557 fTableTopEventRank = fSlider.getSelection();
558 refreshTable();
559 break;
560 }
abbdd66a
AM
561 default:
562 break;
631d853f
PT
563 }
564 }
565 });
566 }
567
568 // ------------------------------------------------------------------------
569 // Simulated Table API
570 // ------------------------------------------------------------------------
571
02023181
MK
572 /**
573 * Method setHeaderVisible.
574 * @param b boolean
575 */
631d853f
PT
576 public void setHeaderVisible(boolean b) {
577 fTable.setHeaderVisible(b);
578 }
579
02023181
MK
580 /**
581 * Method setLinesVisible.
582 * @param b boolean
583 */
631d853f
PT
584 public void setLinesVisible(boolean b) {
585 fTable.setLinesVisible(b);
586 }
587
02023181 588 /**
3934297e 589 * Method getSelection.
02023181
MK
590 * @return TableItem[] the items that are selected.
591 */
631d853f
PT
592 public TableItem[] getSelection() {
593 return fTable.getSelection();
594 }
595
02023181
MK
596 /**
597 * Method addListener.
598 * @param eventType int
599 * @param listener Listener
600 */
631d853f 601 @Override
828e5592
PT
602 public void addListener(int eventType, Listener listener) {
603 fTable.addListener(eventType, listener);
604 }
631d853f 605
02023181
MK
606 /**
607 * Method addKeyListener.
608 * @param listener KeyListener
609 */
631d853f
PT
610 @Override
611 public void addKeyListener(KeyListener listener) {
612 fTable.addKeyListener(listener);
613 }
b21305c2 614
828e5592 615
02023181
MK
616 /**
617 * Method addMouseListener.
618 * @param listener MouseListener
619 */
828e5592 620 @Override
631d853f
PT
621 public void addMouseListener(MouseListener listener) {
622 fTable.addMouseListener(listener);
623 }
624
02023181
MK
625 /**
626 * Method addSelectionListener.
627 * @param listener SelectionListener
628 */
631d853f
PT
629 public void addSelectionListener(SelectionListener listener) {
630 fTable.addSelectionListener(listener);
631 }
632
02023181
MK
633 /**
634 * Method setMenu sets the menu
635 * @param menu Menu the menu
636 */
631d853f
PT
637 @Override
638 public void setMenu(Menu menu) {
639 fTable.setMenu(menu);
640 }
641
48da630d
XR
642 /**
643 * Gets the menu of this table
644 * @return a Menu
645 */
646 @Override
647 public Menu getMenu() {
648 return fTable.getMenu();
649 }
650
02023181 651 /**
3934297e 652 * Method clearAll empties a table.
02023181 653 */
631d853f
PT
654 public void clearAll() {
655 setItemCount(0);
656 }
657
02023181
MK
658 /**
659 * Method setItemCount
660 * @param nbItems int the number of items in the table
3934297e 661 *
02023181 662 */
631d853f 663 public void setItemCount(int nbItems) {
41b5c37f 664 final int nb = Math.max(0, nbItems);
631d853f 665
41b5c37f
AM
666 if (nb != fTableItemCount) {
667 fTableItemCount = nb;
631d853f 668 fTable.remove(fTableItemCount, fTable.getItemCount() - 1);
41b5c37f 669 fSlider.setMaximum(nb);
631d853f
PT
670 resize();
671 int tableHeight = Math.max(0, fTable.getClientArea().height - fTable.getHeaderHeight());
672 fFullyVisibleRows = tableHeight / getItemHeight();
673 if (fTableItemCount > 0) {
674 fSlider.setThumb(Math.max(1, Math.min(fTableRows, fFullyVisibleRows)));
675 }
676 }
677 }
678
02023181
MK
679 /**
680 * Method getItemCount.
681 * @return int the number of items in the table
682 */
631d853f
PT
683 public int getItemCount() {
684 return fTableItemCount;
685 }
686
02023181
MK
687 /**
688 * Method getItemHeight.
689 * @return int the height of a table item in pixels. (may vary from one os to another)
690 */
631d853f
PT
691 public int getItemHeight() {
692 /*
693 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
694 */
695 if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
696 if (fLinuxItemHeight != 0) {
697 return fLinuxItemHeight;
698 }
699 if (fTable.getItemCount() > 1) {
700 int itemHeight = fTable.getItem(1).getBounds().y - fTable.getItem(0).getBounds().y;
701 if (itemHeight > 0) {
702 fLinuxItemHeight = itemHeight;
703 return fLinuxItemHeight;
704 }
705 }
706 } else {
707 fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
708 }
709 return fTable.getItemHeight();
710 }
711
02023181
MK
712 /**
713 * Method getHeaderHeight.
714 * @return int get the height of the header in pixels.
715 */
ea08e8ed
PT
716 public int getHeaderHeight() {
717 return fTable.getHeaderHeight();
718 }
719
02023181
MK
720 /**
721 * Method getTopIndex.
722 * @return int get the first data item index, if you have a header it is offset.
723 */
631d853f
PT
724 public int getTopIndex() {
725 return fTableTopEventRank + fFrozenRowCount;
726 }
727
02023181
MK
728 /**
729 * Method setTopIndex.
41b5c37f 730 * @param index int suggested top index for the table.
02023181 731 */
41b5c37f 732 public void setTopIndex(int index) {
631d853f 733 if (fTableItemCount > 0) {
41b5c37f 734 int i = Math.min(index, fTableItemCount - 1);
631d853f
PT
735 i = Math.max(i, fFrozenRowCount);
736
737 fTableTopEventRank = i - fFrozenRowCount;
738 if (fFullyVisibleRows < fTableItemCount) {
739 fSlider.setSelection(fTableTopEventRank);
740 }
741
742 refreshTable();
743 }
744 }
745
02023181
MK
746 /**
747 * Method indexOf. Return the index of a table item
748 * @param ti TableItem the table item to search for in the table
3934297e 749 * @return int the index of the first match. (there should only be one match)
02023181 750 */
631d853f
PT
751 public int indexOf(TableItem ti) {
752 int index = fTable.indexOf(ti);
753 if (index < fFrozenRowCount) {
754 return index;
631d853f 755 }
abbdd66a 756 return (index - fFrozenRowCount) + getTopIndex();
631d853f
PT
757 }
758
02023181
MK
759 /**
760 * Method getColumns.
3934297e 761 * @return TableColumn[] the table columns
02023181 762 */
631d853f
PT
763 public TableColumn[] getColumns() {
764 return fTable.getColumns();
765 }
766
02023181
MK
767 /**
768 * Method getItem.
769 * @param point Point the coordinates in the table
3934297e 770 * @return TableItem the corresponding table item
02023181 771 */
631d853f
PT
772 public TableItem getItem(Point point) {
773 return fTable.getItem(point);
774 }
775
02023181
MK
776 /**
777 * Method resize.
778 */
631d853f
PT
779 private void resize() {
780 // Compute the numbers of rows that fit the new area
781 int tableHeight = Math.max(0, getSize().y - fTable.getHeaderHeight());
782 int itemHeight = getItemHeight();
783 fTableRows = Math.min((tableHeight + itemHeight - 1) / itemHeight, fTableItemCount);
784
785 if (fTableTopEventRank + fFullyVisibleRows > fTableItemCount) {
786 // If we are at the end, get elements before to populate
787 fTableTopEventRank = Math.max(0, fTableItemCount - fFullyVisibleRows);
788 refreshTable();
789 } else if (fTableRows > fTable.getItemCount() || fTableItemCount < fTable.getItemCount()) {
790 // Only refresh if new table items are needed or if table items need to be deleted
791 refreshTable();
792 }
793
794 }
795
796 // ------------------------------------------------------------------------
797 // Controls interactions
798 // ------------------------------------------------------------------------
799
02023181
MK
800 /**
801 * Method setFocus.
802 * @return boolean is this visible?
803 */
631d853f
PT
804 @Override
805 public boolean setFocus() {
806 boolean isVisible = isVisible();
807 if (isVisible) {
808 fTable.setFocus();
809 }
810 return isVisible;
811 }
812
02023181
MK
813 /**
814 * Method refresh.
815 */
631d853f
PT
816 public void refresh() {
817 boolean done = refreshTable();
818 if (fPendingSelection && done) {
819 fPendingSelection = false;
820 if (fTable.getSelection().length > 0) {
821 Event e = new Event();
822 e.item = fTable.getSelection()[0];
823 fTable.notifyListeners(SWT.Selection, e);
824 }
825 }
826 }
827
02023181
MK
828 /**
829 * Method setColumnHeaders.
3934297e 830 * @param columnData ColumnData[] the columndata array.
02023181 831 */
631d853f
PT
832 public void setColumnHeaders(ColumnData columnData[]) {
833 for (int i = 0; i < columnData.length; i++) {
834 TableColumn column = new TableColumn(fTable, columnData[i].alignment, i);
835 column.setText(columnData[i].header);
b06f64b7
PT
836 /*
837 * In Linux the table does not receive a control resized event when
838 * a table column resize causes the horizontal scroll bar to become
839 * visible or invisible, so a resize listener must be added to every
840 * table column to properly update the number of fully visible rows.
841 */
842 column.addControlListener(fResizeListener);
631d853f
PT
843 if (columnData[i].width > 0) {
844 column.setWidth(columnData[i].width);
845 } else {
846 column.pack();
847 }
848 }
849 }
850
02023181
MK
851 /**
852 * Method removeAll.
853 * @return int 0 the number of elements in the table
854 */
631d853f
PT
855 public int removeAll() {
856 setItemCount(0);
857 fSlider.setMaximum(0);
858 fTable.removeAll();
859 fSelectedEventRank = fFrozenRowCount;
860 return 0;
861 }
862
02023181
MK
863 /**
864 * Method refreshTable.
3934297e 865 * @return boolean did all the items regresh properly?
02023181 866 */
631d853f
PT
867 private boolean refreshTable() {
868 boolean done = true;
869 for (int i = 0; i < fTableRows; i++) {
870 if (i + fTableTopEventRank < fTableItemCount) {
871 TableItem tableItem;
872 if (i < fTable.getItemCount()) {
873 tableItem = fTable.getItem(i);
874 } else {
875 tableItem = new TableItem(fTable, SWT.NONE);
876 }
877 done &= setDataItem(i, tableItem); // false if table item not updated yet in this thread
878 } else {
879 if (fTable.getItemCount() > fTableItemCount - fTableTopEventRank) {
880 fTable.remove(fTableItemCount - fTableTopEventRank);
881 }
882 }
883 }
884
885 int lastRowOffset = fTableTopEventRank + fTableRows - 1;
886 if (fSelectedEventRank < fFrozenRowCount) {
887 fTable.select(fSelectedEventRank);
888 } else if (!done) {
889 fTable.deselectAll();
890 } else if ((fSelectedEventRank >= fTableTopEventRank + fFrozenRowCount) && (fSelectedEventRank <= lastRowOffset)) {
891 int selectedRow = fSelectedEventRank - fTableTopEventRank;
892 fTable.select(selectedRow);
893 } else {
894 fTable.deselectAll();
895 }
896 return done;
897 }
898
02023181
MK
899 /**
900 * Method setSelection.
41b5c37f 901 * @param index int the item number to select in the table.
02023181 902 */
41b5c37f 903 public void setSelection(int index) {
631d853f 904 if (fTableItemCount > 0) {
41b5c37f 905 int i = Math.min(index, fTableItemCount - 1);
631d853f
PT
906 i = Math.max(i, 0);
907
908 fSelectedEventRank = i;
909 if ((i < fTableTopEventRank + fFrozenRowCount && i >= fFrozenRowCount) ||
910 (i >= fTableTopEventRank + fFullyVisibleRows)) {
faa38350
PT
911 int lastPageTopEntryRank = Math.max(0, fTableItemCount - fFullyVisibleRows);
912 fTableTopEventRank = Math.max(0, Math.min(lastPageTopEntryRank, i - fFrozenRowCount - fFullyVisibleRows / 2));
631d853f
PT
913 }
914 if (fFullyVisibleRows < fTableItemCount) {
915 fSlider.setSelection(fTableTopEventRank);
916 }
917
918 refreshTable();
919
920 }
921 }
922
02023181
MK
923 /**
924 * Method getSelectionIndex.
925 * @return int the table index of the selected event. not necessarrily the index of the event due to filtering.
926 */
631d853f
PT
927 public int getSelectionIndex() {
928 int index = fTable.getSelectionIndex();
929 if (index == -1) {
930 return fSelectedEventRank;
931 }
932 if (index < fFrozenRowCount) {
933 return index;
631d853f 934 }
abbdd66a 935 return (index - fFrozenRowCount) + getTopIndex();
631d853f
PT
936 }
937
02023181
MK
938 /**
939 * Method setFrozenRowCount.
940 * @param count int the number of rows to freeze from the top row
941 */
631d853f
PT
942 public void setFrozenRowCount(int count) {
943 fFrozenRowCount = count;
944 refreshTable();
945 }
946
02023181
MK
947 /**
948 * Method createTableEditor.
949 * @return a TableEditor of the table
950 */
631d853f
PT
951 public TableEditor createTableEditor() {
952 return new TableEditor(fTable);
953 }
954
02023181
MK
955 /**
956 * Method createTableEditorControl.
957 * @param control Class<? extends Control>
958 * @return Control
959 */
631d853f
PT
960 public Control createTableEditorControl(Class<? extends Control> control) {
961 try {
420bceb2 962 return control.getConstructor(Composite.class, int.class).newInstance(new Object[] {fTable, SWT.NONE});
631d853f
PT
963 } catch (Exception e) {
964 Activator.getDefault().logError("Error creating table editor control", e); //$NON-NLS-1$
965 }
966 return null;
967 }
968
969 /**
970 * @return the tooltipProvider
02023181 971 */
631d853f
PT
972 public TooltipProvider getTooltipProvider() {
973 return tooltipProvider;
974 }
975
976 /**
977 * @param tooltipProvider the tooltipProvider to set
978 */
979 public void setTooltipProvider(TooltipProvider tooltipProvider) {
980 this.tooltipProvider = tooltipProvider;
981 }
982
983 /**
984 * @return the doubleClickListener
02023181 985 */
631d853f
PT
986 public IDoubleClickListener getDoubleClickListener() {
987 return doubleClickListener;
988 }
989
990 /**
991 * @param doubleClickListener the doubleClickListener to set
992 */
993 public void setDoubleClickListener(IDoubleClickListener doubleClickListener) {
994 this.doubleClickListener = doubleClickListener;
995 }
996
9ccc6d01 997}
This page took 0.087551 seconds and 5 git commands to generate.