Commit | Line | Data |
---|---|---|
853beb54 MK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2015 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 | * Alexandre Montplaisir - Initial API and implementation | |
11 | * Matthew Khouzam - Initial API and implementation | |
12 | *******************************************************************************/ | |
13 | ||
14 | package org.eclipse.tracecompass.tmf.ui.viewers.table; | |
15 | ||
c8688c7f AM |
16 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
17 | import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; | |
18 | ||
19 | import java.util.Collections; | |
8b4318bb | 20 | import java.util.Comparator; |
853beb54 | 21 | |
c8688c7f AM |
22 | import org.eclipse.jdt.annotation.NonNull; |
23 | import org.eclipse.jdt.annotation.Nullable; | |
d857b6bf BH |
24 | import org.eclipse.jface.action.IMenuListener; |
25 | import org.eclipse.jface.action.IMenuManager; | |
26 | import org.eclipse.jface.action.MenuManager; | |
853beb54 MK |
27 | import org.eclipse.jface.viewers.ColumnLabelProvider; |
28 | import org.eclipse.jface.viewers.IContentProvider; | |
c8688c7f | 29 | import org.eclipse.jface.viewers.ILabelProvider; |
d857b6bf BH |
30 | import org.eclipse.jface.viewers.ISelection; |
31 | import org.eclipse.jface.viewers.IStructuredSelection; | |
853beb54 MK |
32 | import org.eclipse.jface.viewers.TableViewer; |
33 | import org.eclipse.jface.viewers.TableViewerColumn; | |
c8688c7f | 34 | import org.eclipse.jface.viewers.Viewer; |
853beb54 MK |
35 | import org.eclipse.jface.viewers.ViewerCell; |
36 | import org.eclipse.jface.viewers.ViewerComparator; | |
c8688c7f | 37 | import org.eclipse.jface.viewers.deferred.DeferredContentProvider; |
853beb54 MK |
38 | import org.eclipse.swt.SWT; |
39 | import org.eclipse.swt.events.MouseAdapter; | |
40 | import org.eclipse.swt.events.MouseEvent; | |
41 | import org.eclipse.swt.events.SelectionAdapter; | |
42 | import org.eclipse.swt.events.SelectionEvent; | |
853beb54 MK |
43 | import org.eclipse.swt.graphics.Point; |
44 | import org.eclipse.swt.widgets.Control; | |
d857b6bf | 45 | import org.eclipse.swt.widgets.Menu; |
853beb54 MK |
46 | import org.eclipse.swt.widgets.Table; |
47 | import org.eclipse.swt.widgets.TableColumn; | |
48 | import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer; | |
49 | ||
50 | /** | |
c8688c7f AM |
51 | * Generic {@link TableViewer} wrapper with most standard features enabled. |
52 | * <p> | |
53 | * It provides the following features: <br> | |
54 | * - Sortable columns <br> | |
55 | * - Movable columns <br> | |
56 | * - Resizable columns <br> | |
57 | * - Tracking last clicked columns | |
58 | * <p> | |
59 | * The user of this class should add columns to the table by using the | |
60 | * {@link #createColumn(String, ColumnLabelProvider, Comparator)} method, and | |
61 | * set the content provider and input on the supplied {@link TableViewer}. | |
853beb54 | 62 | * |
0336f981 | 63 | * @since 1.1 |
853beb54 MK |
64 | */ |
65 | public class TmfSimpleTableViewer extends TmfViewer { | |
66 | ||
c8688c7f AM |
67 | /** |
68 | * Viewer comparator that ignores the element label strings and uses the | |
69 | * given comparator to compare the elements directly. | |
70 | */ | |
71 | private static class ElementComparator extends ViewerComparator { | |
72 | ||
73 | public ElementComparator(Comparator<?> comparator) { | |
74 | super(comparator); | |
75 | } | |
76 | ||
77 | @Override | |
78 | public int compare(Viewer viewer, Object e1, Object e2) { | |
79 | return getComparator().compare(e1, e2); | |
80 | } | |
81 | } | |
82 | ||
83 | /** | |
84 | * Comparator that compares the text of a column given by the label | |
85 | * provider, using the text's String ordering. | |
86 | */ | |
87 | private static class ColumnLabelComparator implements Comparator<Object> { | |
88 | private final ILabelProvider fLabelProvider; | |
89 | ||
90 | public ColumnLabelComparator(ILabelProvider labelProvider) { | |
91 | fLabelProvider = labelProvider; | |
92 | } | |
93 | ||
94 | @Override | |
95 | public int compare(Object o1, Object o2) { | |
96 | String s1 = nullToEmptyString(fLabelProvider.getText(o1)); | |
97 | String s2 = nullToEmptyString(fLabelProvider.getText(o2)); | |
98 | return s1.compareTo(s2); | |
99 | } | |
100 | } | |
101 | ||
853beb54 MK |
102 | private final class MouseColumnListener extends MouseAdapter { |
103 | @Override | |
104 | public void mouseDown(MouseEvent e) { | |
105 | ViewerCell cell = fTableViewer.getCell(new Point(e.x, e.y)); | |
106 | fSelectedColumn = (cell != null) ? cell.getColumnIndex() : -1; | |
107 | } | |
108 | } | |
109 | ||
110 | private final class ColumnSorter extends SelectionAdapter { | |
c8688c7f AM |
111 | private final @NonNull TableColumn fColumn; |
112 | private final @NonNull Comparator<?> fComparator; | |
853beb54 | 113 | |
c8688c7f | 114 | private ColumnSorter(@NonNull TableColumn column, @NonNull Comparator<?> comparator) { |
853beb54 | 115 | fColumn = column; |
c8688c7f | 116 | fComparator = comparator; |
853beb54 MK |
117 | } |
118 | ||
119 | @Override | |
120 | public void widgetSelected(SelectionEvent e) { | |
853beb54 | 121 | Table table = fTableViewer.getTable(); |
853beb54 MK |
122 | TableColumn prevSortcolumn = table.getSortColumn(); |
123 | if (prevSortcolumn == fColumn) { | |
124 | flipSortDirection(); | |
125 | } | |
8b4318bb | 126 | table.setSortDirection(fDirection); |
853beb54 | 127 | table.setSortColumn(fColumn); |
c8688c7f | 128 | Comparator<?> comparator; |
853beb54 | 129 | if (fDirection == SWT.DOWN) { |
c8688c7f | 130 | comparator = fComparator; |
853beb54 | 131 | } else { |
c8688c7f AM |
132 | comparator = checkNotNull(Collections.reverseOrder(fComparator)); |
133 | } | |
134 | IContentProvider contentProvider = fTableViewer.getContentProvider(); | |
135 | if (contentProvider instanceof DeferredContentProvider) { | |
136 | DeferredContentProvider deferredContentProvider = (DeferredContentProvider) contentProvider; | |
137 | deferredContentProvider.setSortOrder(comparator); | |
e332c612 FLN |
138 | } else if (contentProvider instanceof ISortingLazyContentProvider) { |
139 | ISortingLazyContentProvider sortingLazyContentProvider = (ISortingLazyContentProvider) contentProvider; | |
140 | sortingLazyContentProvider.setSortOrder(comparator); | |
c8688c7f AM |
141 | } else { |
142 | fTableViewer.setComparator(new ElementComparator(comparator)); | |
853beb54 | 143 | } |
853beb54 | 144 | } |
853beb54 MK |
145 | } |
146 | ||
147 | private static final int DEFAULT_COL_WIDTH = 200; | |
148 | private final TableViewer fTableViewer; | |
853beb54 MK |
149 | |
150 | private int fDirection; | |
151 | private int fSelectedColumn; | |
152 | ||
d857b6bf BH |
153 | private MenuManager fTablePopupMenuManager; |
154 | ||
853beb54 MK |
155 | /** |
156 | * Constructor that initializes the parent of the viewer | |
157 | * | |
158 | * @param table | |
159 | * the {@link TableViewer} to wrap | |
160 | */ | |
161 | public TmfSimpleTableViewer(TableViewer table) { | |
162 | super(table.getControl().getParent()); | |
163 | fTableViewer = table; | |
853beb54 MK |
164 | |
165 | final Table tableControl = fTableViewer.getTable(); | |
166 | tableControl.setHeaderVisible(true); | |
167 | tableControl.setLinesVisible(true); | |
168 | ||
169 | fDirection = SWT.DOWN; | |
170 | fTableViewer.setUseHashlookup(true); | |
171 | fTableViewer.getControl().addMouseListener(new MouseColumnListener()); | |
d857b6bf BH |
172 | |
173 | fTablePopupMenuManager = new MenuManager(); | |
174 | fTablePopupMenuManager.setRemoveAllWhenShown(true); | |
175 | ||
176 | fTablePopupMenuManager.addMenuListener(new IMenuListener() { | |
177 | @Override | |
178 | public void menuAboutToShow(final @Nullable IMenuManager manager) { | |
179 | TableViewer viewer = getTableViewer(); | |
180 | ISelection selection = viewer.getSelection(); | |
181 | if (selection instanceof IStructuredSelection) { | |
182 | IStructuredSelection sel = (IStructuredSelection) selection; | |
183 | if (manager != null) { | |
184 | appendToTablePopupMenu(manager, sel); | |
185 | } | |
186 | } | |
187 | } | |
188 | }); | |
189 | ||
190 | Menu tablePopup = fTablePopupMenuManager.createContextMenu(getTableViewer().getTable()); | |
191 | getTableViewer().getTable().setMenu(tablePopup); | |
192 | } | |
193 | ||
194 | @Override | |
195 | public void dispose() { | |
196 | if (fTablePopupMenuManager != null) { | |
197 | fTablePopupMenuManager.dispose(); | |
198 | } | |
199 | super.dispose(); | |
200 | } | |
201 | ||
202 | /** | |
203 | * Method to add commands to the context sensitive menu. | |
204 | * @param manager | |
205 | * the menu manager | |
206 | * @param sel | |
207 | * the current selection | |
5dd0ebfe | 208 | * @since 2.0 |
d857b6bf BH |
209 | */ |
210 | protected void appendToTablePopupMenu(@NonNull IMenuManager manager, @NonNull IStructuredSelection sel) { | |
853beb54 MK |
211 | } |
212 | ||
213 | /** | |
c8688c7f AM |
214 | * Create a column for the table. The column will have a default width set, |
215 | * and will be resizable, moveable and sortable. | |
853beb54 MK |
216 | * |
217 | * @param name | |
c8688c7f | 218 | * the name of the column |
853beb54 | 219 | * @param provider |
c8688c7f AM |
220 | * the label provider of the column |
221 | * @param comparator | |
853beb54 | 222 | * the comparator associated with clicking on the column, if it |
c8688c7f AM |
223 | * is null, a string comparator on the label will be used |
224 | * @return the column that was created | |
5dd0ebfe | 225 | * @since 2.0 |
853beb54 | 226 | */ |
c8688c7f | 227 | public final TableColumn createColumn(String name, ColumnLabelProvider provider, @Nullable Comparator<?> comparator) { |
853beb54 MK |
228 | TableViewerColumn col = new TableViewerColumn(fTableViewer, SWT.NONE); |
229 | col.setLabelProvider(provider); | |
230 | final TableColumn column = col.getColumn(); | |
231 | column.setWidth(DEFAULT_COL_WIDTH); | |
232 | column.setText(name); | |
233 | column.setResizable(true); | |
234 | column.setMoveable(true); | |
c8688c7f AM |
235 | if (comparator == null) { |
236 | column.addSelectionListener(new ColumnSorter(column, new ColumnLabelComparator(provider))); | |
237 | } else { | |
238 | column.addSelectionListener(new ColumnSorter(column, comparator)); | |
239 | } | |
240 | return column; | |
853beb54 MK |
241 | } |
242 | ||
8b4318bb FLN |
243 | /** |
244 | * Reverse the sort direction | |
245 | */ | |
853beb54 MK |
246 | private void flipSortDirection() { |
247 | if (fDirection == SWT.DOWN) { | |
248 | fDirection = SWT.UP; | |
249 | } else { | |
250 | fDirection = SWT.DOWN; | |
251 | } | |
853beb54 MK |
252 | } |
253 | ||
853beb54 MK |
254 | @Override |
255 | public final Control getControl() { | |
256 | return fTableViewer.getControl(); | |
257 | } | |
258 | ||
259 | /** | |
260 | * Gets the wrapped table viewer | |
261 | * | |
262 | * @return the table viewer | |
263 | */ | |
264 | public final TableViewer getTableViewer() { | |
265 | return fTableViewer; | |
266 | } | |
267 | ||
268 | /** | |
269 | * Get the selected column index | |
270 | * | |
271 | * @return the selected column index or -1 | |
272 | */ | |
273 | public final int getColumnIndex() { | |
274 | return fSelectedColumn; | |
275 | } | |
276 | ||
277 | @Override | |
278 | public final void refresh() { | |
279 | fTableViewer.refresh(); | |
280 | } | |
8b4318bb | 281 | } |