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 | */ | |
ed493a07 | 71 | private static class ElementComparator<T> extends ViewerComparator { |
c8688c7f | 72 | |
ed493a07 PT |
73 | private Comparator<T> elementComparator; |
74 | ||
75 | public ElementComparator(Comparator<T> comparator) { | |
76 | elementComparator = comparator; | |
c8688c7f AM |
77 | } |
78 | ||
ed493a07 | 79 | @SuppressWarnings("unchecked") |
c8688c7f AM |
80 | @Override |
81 | public int compare(Viewer viewer, Object e1, Object e2) { | |
ed493a07 | 82 | return elementComparator.compare((T) e1, (T) e2); |
c8688c7f AM |
83 | } |
84 | } | |
85 | ||
86 | /** | |
87 | * Comparator that compares the text of a column given by the label | |
88 | * provider, using the text's String ordering. | |
89 | */ | |
90 | private static class ColumnLabelComparator implements Comparator<Object> { | |
91 | private final ILabelProvider fLabelProvider; | |
92 | ||
93 | public ColumnLabelComparator(ILabelProvider labelProvider) { | |
94 | fLabelProvider = labelProvider; | |
95 | } | |
96 | ||
97 | @Override | |
98 | public int compare(Object o1, Object o2) { | |
99 | String s1 = nullToEmptyString(fLabelProvider.getText(o1)); | |
100 | String s2 = nullToEmptyString(fLabelProvider.getText(o2)); | |
101 | return s1.compareTo(s2); | |
102 | } | |
103 | } | |
104 | ||
853beb54 MK |
105 | private final class MouseColumnListener extends MouseAdapter { |
106 | @Override | |
107 | public void mouseDown(MouseEvent e) { | |
108 | ViewerCell cell = fTableViewer.getCell(new Point(e.x, e.y)); | |
109 | fSelectedColumn = (cell != null) ? cell.getColumnIndex() : -1; | |
110 | } | |
111 | } | |
112 | ||
ed493a07 | 113 | private final class ColumnSorter<T> extends SelectionAdapter { |
c8688c7f | 114 | private final @NonNull TableColumn fColumn; |
ed493a07 | 115 | private final @NonNull Comparator<T> fComparator; |
853beb54 | 116 | |
ed493a07 | 117 | private ColumnSorter(@NonNull TableColumn column, @NonNull Comparator<T> comparator) { |
853beb54 | 118 | fColumn = column; |
c8688c7f | 119 | fComparator = comparator; |
853beb54 MK |
120 | } |
121 | ||
122 | @Override | |
123 | public void widgetSelected(SelectionEvent e) { | |
853beb54 | 124 | Table table = fTableViewer.getTable(); |
853beb54 MK |
125 | TableColumn prevSortcolumn = table.getSortColumn(); |
126 | if (prevSortcolumn == fColumn) { | |
127 | flipSortDirection(); | |
128 | } | |
8b4318bb | 129 | table.setSortDirection(fDirection); |
853beb54 | 130 | table.setSortColumn(fColumn); |
ed493a07 | 131 | Comparator<T> comparator; |
853beb54 | 132 | if (fDirection == SWT.DOWN) { |
c8688c7f | 133 | comparator = fComparator; |
853beb54 | 134 | } else { |
c8688c7f AM |
135 | comparator = checkNotNull(Collections.reverseOrder(fComparator)); |
136 | } | |
137 | IContentProvider contentProvider = fTableViewer.getContentProvider(); | |
138 | if (contentProvider instanceof DeferredContentProvider) { | |
139 | DeferredContentProvider deferredContentProvider = (DeferredContentProvider) contentProvider; | |
140 | deferredContentProvider.setSortOrder(comparator); | |
e332c612 FLN |
141 | } else if (contentProvider instanceof ISortingLazyContentProvider) { |
142 | ISortingLazyContentProvider sortingLazyContentProvider = (ISortingLazyContentProvider) contentProvider; | |
143 | sortingLazyContentProvider.setSortOrder(comparator); | |
c8688c7f | 144 | } else { |
ed493a07 | 145 | fTableViewer.setComparator(new ElementComparator<>(comparator)); |
853beb54 | 146 | } |
853beb54 | 147 | } |
853beb54 MK |
148 | } |
149 | ||
150 | private static final int DEFAULT_COL_WIDTH = 200; | |
151 | private final TableViewer fTableViewer; | |
853beb54 MK |
152 | |
153 | private int fDirection; | |
154 | private int fSelectedColumn; | |
155 | ||
d857b6bf BH |
156 | private MenuManager fTablePopupMenuManager; |
157 | ||
853beb54 MK |
158 | /** |
159 | * Constructor that initializes the parent of the viewer | |
160 | * | |
161 | * @param table | |
162 | * the {@link TableViewer} to wrap | |
163 | */ | |
164 | public TmfSimpleTableViewer(TableViewer table) { | |
165 | super(table.getControl().getParent()); | |
166 | fTableViewer = table; | |
853beb54 MK |
167 | |
168 | final Table tableControl = fTableViewer.getTable(); | |
169 | tableControl.setHeaderVisible(true); | |
170 | tableControl.setLinesVisible(true); | |
171 | ||
172 | fDirection = SWT.DOWN; | |
173 | fTableViewer.setUseHashlookup(true); | |
174 | fTableViewer.getControl().addMouseListener(new MouseColumnListener()); | |
d857b6bf BH |
175 | |
176 | fTablePopupMenuManager = new MenuManager(); | |
177 | fTablePopupMenuManager.setRemoveAllWhenShown(true); | |
178 | ||
179 | fTablePopupMenuManager.addMenuListener(new IMenuListener() { | |
180 | @Override | |
181 | public void menuAboutToShow(final @Nullable IMenuManager manager) { | |
182 | TableViewer viewer = getTableViewer(); | |
183 | ISelection selection = viewer.getSelection(); | |
184 | if (selection instanceof IStructuredSelection) { | |
185 | IStructuredSelection sel = (IStructuredSelection) selection; | |
186 | if (manager != null) { | |
187 | appendToTablePopupMenu(manager, sel); | |
188 | } | |
189 | } | |
190 | } | |
191 | }); | |
192 | ||
193 | Menu tablePopup = fTablePopupMenuManager.createContextMenu(getTableViewer().getTable()); | |
194 | getTableViewer().getTable().setMenu(tablePopup); | |
195 | } | |
196 | ||
197 | @Override | |
198 | public void dispose() { | |
b3ddb2d0 AM |
199 | if (fTableViewer != null) { |
200 | fTableViewer.getControl().dispose(); | |
201 | } | |
d857b6bf BH |
202 | if (fTablePopupMenuManager != null) { |
203 | fTablePopupMenuManager.dispose(); | |
204 | } | |
205 | super.dispose(); | |
206 | } | |
207 | ||
208 | /** | |
209 | * Method to add commands to the context sensitive menu. | |
210 | * @param manager | |
211 | * the menu manager | |
212 | * @param sel | |
213 | * the current selection | |
5dd0ebfe | 214 | * @since 2.0 |
d857b6bf BH |
215 | */ |
216 | protected void appendToTablePopupMenu(@NonNull IMenuManager manager, @NonNull IStructuredSelection sel) { | |
853beb54 MK |
217 | } |
218 | ||
219 | /** | |
c8688c7f AM |
220 | * Create a column for the table. The column will have a default width set, |
221 | * and will be resizable, moveable and sortable. | |
853beb54 MK |
222 | * |
223 | * @param name | |
c8688c7f | 224 | * the name of the column |
853beb54 | 225 | * @param provider |
c8688c7f AM |
226 | * the label provider of the column |
227 | * @param comparator | |
853beb54 | 228 | * the comparator associated with clicking on the column, if it |
c8688c7f AM |
229 | * is null, a string comparator on the label will be used |
230 | * @return the column that was created | |
5dd0ebfe | 231 | * @since 2.0 |
853beb54 | 232 | */ |
ed493a07 | 233 | public final <T> TableColumn createColumn(String name, ColumnLabelProvider provider, @Nullable Comparator<T> comparator) { |
853beb54 MK |
234 | TableViewerColumn col = new TableViewerColumn(fTableViewer, SWT.NONE); |
235 | col.setLabelProvider(provider); | |
236 | final TableColumn column = col.getColumn(); | |
237 | column.setWidth(DEFAULT_COL_WIDTH); | |
238 | column.setText(name); | |
239 | column.setResizable(true); | |
240 | column.setMoveable(true); | |
c8688c7f | 241 | if (comparator == null) { |
ed493a07 | 242 | column.addSelectionListener(new ColumnSorter<>(column, new ColumnLabelComparator(provider))); |
c8688c7f | 243 | } else { |
ed493a07 | 244 | column.addSelectionListener(new ColumnSorter<>(column, comparator)); |
c8688c7f AM |
245 | } |
246 | return column; | |
853beb54 MK |
247 | } |
248 | ||
8b4318bb FLN |
249 | /** |
250 | * Reverse the sort direction | |
251 | */ | |
853beb54 MK |
252 | private void flipSortDirection() { |
253 | if (fDirection == SWT.DOWN) { | |
254 | fDirection = SWT.UP; | |
255 | } else { | |
256 | fDirection = SWT.DOWN; | |
257 | } | |
853beb54 MK |
258 | } |
259 | ||
853beb54 MK |
260 | @Override |
261 | public final Control getControl() { | |
262 | return fTableViewer.getControl(); | |
263 | } | |
264 | ||
265 | /** | |
266 | * Gets the wrapped table viewer | |
267 | * | |
268 | * @return the table viewer | |
269 | */ | |
270 | public final TableViewer getTableViewer() { | |
271 | return fTableViewer; | |
272 | } | |
273 | ||
274 | /** | |
275 | * Get the selected column index | |
276 | * | |
277 | * @return the selected column index or -1 | |
278 | */ | |
279 | public final int getColumnIndex() { | |
280 | return fSelectedColumn; | |
281 | } | |
282 | ||
283 | @Override | |
284 | public final void refresh() { | |
285 | fTableViewer.refresh(); | |
286 | } | |
8b4318bb | 287 | } |