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