1 /*******************************************************************************
2 * Copyright (c) 2010 Ericsson
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
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 ******************************************************************************/
16 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.virtualtable
;
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
;
51 * <b><u>TmfVirtualTable</u></b>
53 * TmfVirtualTable allows for the tabular display of arbitrarily large data sets
54 * (well, up to Integer.MAX_VALUE or ~2G rows).
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.
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.
63 * H_SCROLL, V_SCROLL, SINGLE, CHECK, FULL_SELECTION, HIDE_SELECTION, NO_SCROLL
65 public class TmfVirtualTable
extends Composite
{
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
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
77 private int fTableItemCount
= 0;
80 private Slider fSlider
;
82 private int fLinuxItemHeight
= 0; // Calculated item height for Linux workaround
83 private TooltipProvider tooltipProvider
= null;
84 private IDoubleClickListener doubleClickListener
= null;
86 // ------------------------------------------------------------------------
88 // ------------------------------------------------------------------------
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
));
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
);
101 // Prevent the slider from being traversed
102 setTabList(new Control
[] { fTable
});
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
);
113 GridData tableGridData
= new GridData(SWT
.FILL
, SWT
.FILL
, true, true);
114 fTable
.setLayoutData(tableGridData
);
116 GridData sliderGridData
= new GridData(SWT
.FILL
, SWT
.FILL
, false, true);
117 fSlider
.setLayoutData(sliderGridData
);
120 fTable
.addMouseWheelListener(new MouseWheelListener() {
122 public void mouseScrolled(MouseEvent event
) {
123 if (fTableItemCount
<= fFullyVisibleRows
) {
126 fTableTopEventRank
-= event
.count
;
127 if (fTableTopEventRank
< 0) {
128 fTableTopEventRank
= 0;
130 int latestFirstRowOffset
= fTableItemCount
- fFullyVisibleRows
;
131 if (fTableTopEventRank
> latestFirstRowOffset
) {
132 fTableTopEventRank
= latestFirstRowOffset
;
135 fSlider
.setSelection(fTableTopEventRank
);
140 fTable
.addListener(SWT
.MouseWheel
, new Listener() {
141 // disable mouse scroll of horizontal scroll bar
143 public void handleEvent(Event event
) {
148 fTable
.addControlListener(new ControlAdapter() {
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
)));
158 // Implement a "fake" tooltip
159 final String TOOLTIP_DATA_KEY
= "_TABLEITEM"; //$NON-NLS-1$
160 final Listener labelListener
= new Listener () {
162 public void handleEvent (Event event
) {
163 Label label
= (Label
)event
.widget
;
164 Shell shell
= label
.getShell ();
165 switch (event
.type
) {
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
);
184 Listener tableListener
= new Listener () {
188 public void handleEvent (Event event
) {
189 switch (event
.type
) {
192 case SWT
.MouseMove
: {
201 case SWT
.MouseHover
: {
202 TableItem item
= fTable
.getItem (new Point(event
.x
, event
.y
));
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()) {
210 if (tooltipProvider
== null) {
213 String tooltipText
= tooltipProvider
.getTooltip(i
, item
.getData());
214 if (tooltipText
== null) {
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
);
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);
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() {
250 public void controlResized(ControlEvent event
) {
252 if (fTableItemCount
> 0) {
253 fSlider
.setThumb(Math
.max(1, Math
.min(fTableRows
, fFullyVisibleRows
)));
262 // ------------------------------------------------------------------------
264 // ------------------------------------------------------------------------
267 * Create the table and add listeners
269 private void createTable(int style
) {
270 fTable
= new Table(this, style
| SWT
.NO_SCROLL
);
272 fTable
.addSelectionListener(new SelectionAdapter() {
274 public void widgetSelected(SelectionEvent event
) {
275 if (fTable
.getSelectionIndices().length
> 0) {
276 handleTableSelection();
281 fTable
.addKeyListener(new KeyListener() {
283 public void keyPressed(KeyEvent event
) {
284 handleTableKeyEvent(event
);
287 public void keyReleased(KeyEvent event
) {
292 SWT
.MouseDoubleClick
, new Listener() {
294 public void handleEvent(Event event
) {
295 if (doubleClickListener
!= null) {
296 TableItem item
= fTable
.getItem (new Point (event
.x
, event
.y
));
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
);
313 * Update the rows and selected item
315 private void handleTableSelection() {
316 int selectedRow
= fTable
.getSelectionIndices()[0];
317 if (selectedRow
< fFrozenRowCount
) {
318 fSelectedEventRank
= selectedRow
;
320 fSelectedEventRank
= fTableTopEventRank
+ selectedRow
;
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.
330 if (selectedRow
>= fFullyVisibleRows
) {
331 final Display display
= fTable
.getDisplay();
332 Thread thread
= new Thread("Top index check") { //$NON-NLS-1$
337 } catch (InterruptedException e
) {
339 display
.asyncExec(new Runnable() {
342 if (fTable
.isDisposed()) {
345 int topIndex
= fTable
.getTopIndex();
347 fTableTopEventRank
+= topIndex
;
349 fSlider
.setSelection(fTableTopEventRank
);
350 fTable
.setTopIndex(0);
361 * Handle key-based navigation in table.
365 private void handleTableKeyEvent(KeyEvent event
) {
367 int lastEventRank
= fTableItemCount
- 1;
368 int lastPageTopEntryRank
= Math
.max(0, fTableItemCount
- fFullyVisibleRows
);
370 int previousSelectedEventRank
= fSelectedEventRank
;
371 int selectedRow
= fSelectedEventRank
- fTableTopEventRank
;
372 boolean needsRefresh
= false;
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
) {
381 case SWT
.ARROW_DOWN
: {
383 if (fSelectedEventRank
< lastEventRank
) {
384 fSelectedEventRank
++;
385 selectedRow
= fSelectedEventRank
- fTableTopEventRank
;
386 if (selectedRow
>= fFullyVisibleRows
) {
387 fTableTopEventRank
++;
396 if (fSelectedEventRank
> 0) {
397 fSelectedEventRank
--;
398 selectedRow
= fSelectedEventRank
- fTableTopEventRank
;
399 if (selectedRow
< fFrozenRowCount
&& fTableTopEventRank
> 0) {
400 fTableTopEventRank
--;
409 fTableTopEventRank
= lastPageTopEntryRank
;
410 fSelectedEventRank
= lastEventRank
;
417 fSelectedEventRank
= fFrozenRowCount
;
418 fTableTopEventRank
= 0;
423 case SWT
.PAGE_DOWN
: {
425 if (fSelectedEventRank
< lastEventRank
) {
426 fSelectedEventRank
+= fFullyVisibleRows
;
427 if (fSelectedEventRank
> lastEventRank
) {
428 fSelectedEventRank
= lastEventRank
;
430 selectedRow
= fSelectedEventRank
- fTableTopEventRank
;
431 if (selectedRow
> fFullyVisibleRows
- 1) {
432 fTableTopEventRank
+= fFullyVisibleRows
;
433 if (fTableTopEventRank
> lastPageTopEntryRank
) {
434 fTableTopEventRank
= lastPageTopEntryRank
;
444 if (fSelectedEventRank
> 0) {
445 fSelectedEventRank
-= fFullyVisibleRows
;
446 if (fSelectedEventRank
< fFrozenRowCount
) {
447 fSelectedEventRank
= fFrozenRowCount
;
449 selectedRow
= fSelectedEventRank
- fTableTopEventRank
;
450 if (selectedRow
< 0) {
451 fTableTopEventRank
-= fFullyVisibleRows
;
452 if (fTableTopEventRank
< 0) {
453 fTableTopEventRank
= 0;
467 done
= refreshTable(); // false if table items not updated yet in this thread
469 fTable
.select(selectedRow
);
472 if (fFullyVisibleRows
< fTableItemCount
) {
473 fSlider
.setSelection(fTableTopEventRank
);
476 if (fSelectedEventRank
!= previousSelectedEventRank
&& fSelectedEventRank
< fTableItemCount
) {
478 Event e
= new Event();
479 e
.item
= fTable
.getSelection()[0];
480 fTable
.notifyListeners(SWT
.Selection
, e
);
482 fPendingSelection
= true;
487 private boolean setDataItem(int index
, TableItem item
) {
489 Event event
= new Event();
491 if (index
< fFrozenRowCount
) {
494 event
.index
= index
+ fTableTopEventRank
;
497 fTable
.notifyListeners(SWT
.SetData
, event
);
498 return event
.doit
; // false if table item not updated yet in this thread
503 // ------------------------------------------------------------------------
505 // ------------------------------------------------------------------------
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);
515 fSlider
.addListener(SWT
.Selection
, new Listener() {
517 public void handleEvent(Event event
) {
518 switch (event
.detail
) {
526 fTableTopEventRank
= fSlider
.getSelection();
535 // ------------------------------------------------------------------------
536 // Simulated Table API
537 // ------------------------------------------------------------------------
539 public void setHeaderVisible(boolean b
) {
540 fTable
.setHeaderVisible(b
);
543 public void setLinesVisible(boolean b
) {
544 fTable
.setLinesVisible(b
);
547 public TableItem
[] getSelection() {
548 return fTable
.getSelection();
552 public void addListener(int eventType
, Listener listener
) {
553 fTable
.addListener(eventType
, listener
);
557 public void addKeyListener(KeyListener listener
) {
558 fTable
.addKeyListener(listener
);
563 public void addMouseListener(MouseListener listener
) {
564 fTable
.addMouseListener(listener
);
567 public void addSelectionListener(SelectionListener listener
) {
568 fTable
.addSelectionListener(listener
);
572 public void setMenu(Menu menu
) {
573 fTable
.setMenu(menu
);
576 public void clearAll() {
580 public void setItemCount(int nbItems
) {
581 nbItems
= Math
.max(0, nbItems
);
583 if (nbItems
!= fTableItemCount
) {
584 fTableItemCount
= nbItems
;
585 fTable
.remove(fTableItemCount
, fTable
.getItemCount() - 1);
586 fSlider
.setMaximum(nbItems
);
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
)));
596 public int getItemCount() {
597 return fTableItemCount
;
600 public int getItemHeight() {
602 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
604 if (fLinuxItemHeight
>= 0 && System
.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
605 if (fLinuxItemHeight
!= 0) {
606 return fLinuxItemHeight
;
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
;
616 fLinuxItemHeight
= -1; // Not Linux, don't perform os.name check anymore
618 return fTable
.getItemHeight();
621 public int getHeaderHeight() {
622 return fTable
.getHeaderHeight();
625 public int getTopIndex() {
626 return fTableTopEventRank
+ fFrozenRowCount
;
629 public void setTopIndex(int i
) {
630 if (fTableItemCount
> 0) {
631 i
= Math
.min(i
, fTableItemCount
- 1);
632 i
= Math
.max(i
, fFrozenRowCount
);
634 fTableTopEventRank
= i
- fFrozenRowCount
;
635 if (fFullyVisibleRows
< fTableItemCount
) {
636 fSlider
.setSelection(fTableTopEventRank
);
643 public int indexOf(TableItem ti
) {
644 int index
= fTable
.indexOf(ti
);
645 if (index
< fFrozenRowCount
) {
648 return (index
- fFrozenRowCount
) + getTopIndex();
652 public TableColumn
[] getColumns() {
653 return fTable
.getColumns();
656 public TableItem
getItem(Point point
) {
657 return fTable
.getItem(point
);
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
);
666 if (fTableTopEventRank
+ fFullyVisibleRows
> fTableItemCount
) {
667 // If we are at the end, get elements before to populate
668 fTableTopEventRank
= Math
.max(0, fTableItemCount
- fFullyVisibleRows
);
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
677 // ------------------------------------------------------------------------
678 // Controls interactions
679 // ------------------------------------------------------------------------
682 public boolean setFocus() {
683 boolean isVisible
= isVisible();
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
);
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
);
714 public int removeAll() {
716 fSlider
.setMaximum(0);
718 fSelectedEventRank
= fFrozenRowCount
;
722 private boolean refreshTable() {
724 for (int i
= 0; i
< fTableRows
; i
++) {
725 if (i
+ fTableTopEventRank
< fTableItemCount
) {
727 if (i
< fTable
.getItemCount()) {
728 tableItem
= fTable
.getItem(i
);
730 tableItem
= new TableItem(fTable
, SWT
.NONE
);
732 done
&= setDataItem(i
, tableItem
); // false if table item not updated yet in this thread
734 if (fTable
.getItemCount() > fTableItemCount
- fTableTopEventRank
) {
735 fTable
.remove(fTableItemCount
- fTableTopEventRank
);
740 int lastRowOffset
= fTableTopEventRank
+ fTableRows
- 1;
741 if (fSelectedEventRank
< fFrozenRowCount
) {
742 fTable
.select(fSelectedEventRank
);
744 fTable
.deselectAll();
745 } else if ((fSelectedEventRank
>= fTableTopEventRank
+ fFrozenRowCount
) && (fSelectedEventRank
<= lastRowOffset
)) {
746 int selectedRow
= fSelectedEventRank
- fTableTopEventRank
;
747 fTable
.select(selectedRow
);
749 fTable
.deselectAll();
754 public void setSelection(int i
) {
755 if (fTableItemCount
> 0) {
756 i
= Math
.min(i
, fTableItemCount
- 1);
759 fSelectedEventRank
= i
;
760 if ((i
< fTableTopEventRank
+ fFrozenRowCount
&& i
>= fFrozenRowCount
) ||
761 (i
>= fTableTopEventRank
+ fFullyVisibleRows
)) {
762 fTableTopEventRank
= Math
.max(0, i
- fFrozenRowCount
- fFullyVisibleRows
/ 2);
764 if (fFullyVisibleRows
< fTableItemCount
) {
765 fSlider
.setSelection(fTableTopEventRank
);
773 public int getSelectionIndex() {
774 int index
= fTable
.getSelectionIndex();
776 return fSelectedEventRank
;
778 if (index
< fFrozenRowCount
) {
781 return (index
- fFrozenRowCount
) + getTopIndex();
785 public void setFrozenRowCount(int count
) {
786 fFrozenRowCount
= count
;
790 public TableEditor
createTableEditor() {
791 return new TableEditor(fTable
);
794 public Control
createTableEditorControl(Class
<?
extends Control
> control
) {
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$
804 * @return the tooltipProvider
806 public TooltipProvider
getTooltipProvider() {
807 return tooltipProvider
;
811 * @param tooltipProvider the tooltipProvider to set
813 public void setTooltipProvider(TooltipProvider tooltipProvider
) {
814 this.tooltipProvider
= tooltipProvider
;
818 * @return the doubleClickListener
820 public IDoubleClickListener
getDoubleClickListener() {
821 return doubleClickListener
;
825 * @param doubleClickListener the doubleClickListener to set
827 public void setDoubleClickListener(IDoubleClickListener doubleClickListener
) {
828 this.doubleClickListener
= doubleClickListener
;