Commit | Line | Data |
---|---|---|
4208b510 AM |
1 | /******************************************************************************* |
2 | * Copyright (c) 2015, 2016 Ericsson, EfficiOS Inc. and others | |
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 | ||
10 | package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers; | |
11 | ||
682c435f | 12 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
4208b510 AM |
13 | import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; |
14 | ||
15 | import java.util.HashSet; | |
16 | import java.util.List; | |
17 | import java.util.Set; | |
18 | ||
19 | import org.eclipse.jdt.annotation.Nullable; | |
20 | import org.eclipse.jface.viewers.ColumnLabelProvider; | |
21 | import org.eclipse.jface.viewers.IStructuredSelection; | |
22 | import org.eclipse.jface.viewers.StructuredSelection; | |
23 | import org.eclipse.jface.viewers.TableViewer; | |
24 | import org.eclipse.swt.SWT; | |
25 | import org.eclipse.swt.events.SelectionAdapter; | |
26 | import org.eclipse.swt.events.SelectionEvent; | |
27 | import org.eclipse.swt.widgets.Display; | |
28 | import org.eclipse.swt.widgets.TableColumn; | |
29 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.aspect.LamiTableEntryAspect; | |
4208b510 AM |
30 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiTableEntry; |
31 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.signals.LamiSelectionUpdateSignal; | |
32 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.views.LamiReportView; | |
3f506e25 | 33 | import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.views.LamiReportViewTabPage; |
682c435f | 34 | import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.signal.ChartSelectionUpdateSignal; |
4208b510 AM |
35 | import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; |
36 | import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; | |
37 | import org.eclipse.tracecompass.tmf.ui.viewers.table.TmfSimpleTableViewer; | |
38 | ||
39 | /** | |
40 | * Table viewer to use in {@link LamiReportView}s. | |
41 | * | |
42 | * @author Alexandre Montplaisir | |
682c435f | 43 | * @author Gabriel-Andrew Pollo-Guilbert |
4208b510 AM |
44 | */ |
45 | public final class LamiTableViewer extends TmfSimpleTableViewer implements ILamiViewer { | |
46 | ||
47 | // ------------------------------------------------------------------------ | |
48 | // Attributes | |
49 | // ------------------------------------------------------------------------ | |
50 | ||
3f506e25 | 51 | private final LamiReportViewTabPage fPage; |
4208b510 | 52 | private Set<Integer> fSelections; |
682c435f | 53 | private Set<Object> fSelection; |
4208b510 AM |
54 | |
55 | // ------------------------------------------------------------------------ | |
56 | // Inner class definitions | |
57 | // ------------------------------------------------------------------------ | |
58 | ||
59 | /** | |
60 | * Abstract class for the column label provider for the latency analysis | |
682c435f | 61 | * table viewer. |
4208b510 AM |
62 | */ |
63 | private static class LamiTableColumnLabelProvider extends ColumnLabelProvider { | |
4208b510 AM |
64 | private final LamiTableEntryAspect fColumnAspect; |
65 | ||
66 | public LamiTableColumnLabelProvider(LamiTableEntryAspect aspect) { | |
67 | fColumnAspect = aspect; | |
68 | } | |
69 | ||
70 | @Override | |
71 | public String getText(@Nullable Object input) { | |
682c435f | 72 | /* Doubles as a null check */ |
4208b510 | 73 | if (!(input instanceof LamiTableEntry)) { |
4208b510 AM |
74 | return ""; //$NON-NLS-1$ |
75 | } | |
682c435f GAPG |
76 | |
77 | return nullToEmptyString(fColumnAspect.resolveString((LamiTableEntry) input)); | |
4208b510 AM |
78 | } |
79 | } | |
80 | ||
81 | /** | |
682c435f GAPG |
82 | * Listener to update in other viewers when a cell of the latency table view |
83 | * is selected. | |
4208b510 AM |
84 | */ |
85 | private class LamiTableSelectionListener extends SelectionAdapter { | |
86 | @Override | |
682c435f | 87 | public void widgetSelected(@Nullable SelectionEvent event) { |
4208b510 AM |
88 | IStructuredSelection selections = getTableViewer().getStructuredSelection(); |
89 | ||
682c435f | 90 | // Lami selections |
4208b510 AM |
91 | Set<Integer> selectionIndexes = new HashSet<>(); |
92 | for (Object selectedEntry : selections.toArray() ) { | |
3f506e25 | 93 | selectionIndexes.add(fPage.getResultTable().getEntries().indexOf(selectedEntry)); |
4208b510 AM |
94 | } |
95 | ||
96 | fSelections = selectionIndexes; | |
97 | ||
98 | /* Signal all Lami viewers & views of the selection */ | |
3f506e25 | 99 | LamiSelectionUpdateSignal signal = new LamiSelectionUpdateSignal(LamiTableViewer.this, selectionIndexes, fPage); |
4208b510 | 100 | TmfSignalManager.dispatchSignal(signal); |
682c435f GAPG |
101 | |
102 | /* Find all selected entries */ | |
103 | Set<Object> selectionSet = new HashSet<>(); | |
104 | for (Object selectedEntry : selections.toArray()) { | |
105 | selectionSet.add(checkNotNull(selectedEntry)); | |
106 | } | |
107 | fSelection = selectionSet; | |
108 | ||
109 | ||
110 | /* Signal all Lami viewers & views of the selection */ | |
111 | ChartSelectionUpdateSignal customSignal = new ChartSelectionUpdateSignal(LamiTableViewer.this, fPage.getResultTable(), selectionSet); | |
112 | TmfSignalManager.dispatchSignal(customSignal); | |
4208b510 AM |
113 | } |
114 | } | |
115 | ||
116 | // ------------------------------------------------------------------------ | |
682c435f | 117 | // Constructors |
4208b510 AM |
118 | // ------------------------------------------------------------------------ |
119 | ||
120 | /** | |
121 | * Constructor | |
122 | * | |
123 | * @param tableViewer | |
124 | * Table viewer of the view | |
3f506e25 JR |
125 | * @param page |
126 | * The {@link LamiReportViewTabPage} parent page | |
4208b510 | 127 | */ |
3f506e25 | 128 | public LamiTableViewer(TableViewer tableViewer, LamiReportViewTabPage page) { |
4208b510 | 129 | super(tableViewer); |
682c435f GAPG |
130 | |
131 | /* The viewer should always be the first element in the control. */ | |
4208b510 AM |
132 | tableViewer.getTable().moveAbove(null); |
133 | ||
3f506e25 | 134 | fPage = page; |
4208b510 | 135 | fSelections = new HashSet<>(); |
682c435f | 136 | fSelection = new HashSet<>(); |
4208b510 AM |
137 | |
138 | /* Default sort order of the content provider is by its first column */ | |
139 | getTableViewer().setContentProvider(new LamiTableContentProvider()); | |
140 | getTableViewer().getTable().addSelectionListener(new LamiTableSelectionListener()); | |
141 | ||
142 | createColumns(); | |
143 | fillData(); | |
144 | } | |
145 | ||
146 | // ------------------------------------------------------------------------ | |
147 | // Operations | |
148 | // ------------------------------------------------------------------------ | |
149 | ||
150 | private void createColumns() { | |
3f506e25 | 151 | final List<LamiTableEntryAspect> aspects = fPage.getResultTable().getTableClass().getAspects(); |
4208b510 AM |
152 | |
153 | Display.getDefault().asyncExec(new Runnable() { | |
154 | @Override | |
155 | public void run() { | |
156 | for (LamiTableEntryAspect aspect : aspects) { | |
157 | createColumn(aspect.getLabel(), new LamiTableColumnLabelProvider(aspect), aspect.getComparator()); | |
158 | } | |
159 | } | |
160 | }); | |
161 | } | |
162 | ||
163 | /** | |
164 | * Update the data in the table viewer | |
165 | * | |
166 | * @param dataInput | |
167 | * New data input | |
168 | */ | |
169 | private void fillData() { | |
170 | final TableViewer tableViewer = getTableViewer(); | |
171 | Display.getDefault().asyncExec(() -> { | |
172 | if (tableViewer.getTable().isDisposed()) { | |
173 | return; | |
174 | } | |
175 | // Go to the top of the table | |
176 | tableViewer.getTable().setTopIndex(0); | |
177 | // Reset selected row | |
178 | tableViewer.setSelection(StructuredSelection.EMPTY); | |
179 | ||
180 | /* Fill the table data */ | |
3f506e25 | 181 | tableViewer.setInput(fPage.getResultTable().getEntries()); |
4208b510 AM |
182 | LamiTableContentProvider latencyContentProvider = (LamiTableContentProvider) getTableViewer().getContentProvider(); |
183 | tableViewer.setItemCount(latencyContentProvider.getNbEntries()); | |
184 | ||
185 | /* Set the column's alignment and pack them */ | |
186 | TableColumn[] cols = tableViewer.getTable().getColumns(); | |
187 | for (int i = 0; i < cols.length; i++) { | |
3f506e25 | 188 | LamiTableEntryAspect colAspect = fPage.getResultTable().getTableClass().getAspects().get(i); |
4208b510 AM |
189 | int alignment = (colAspect.isContinuous() ? SWT.RIGHT : SWT.LEFT); |
190 | cols[i].setAlignment(alignment); | |
191 | ||
192 | } | |
193 | ||
194 | /* | |
195 | * On creation check if there is selections if so update the table | |
196 | * selections here. Selections needs the ContentProvider for valid | |
197 | * index lookup and since the content provider is set in an | |
198 | * asynchronous task we cannot use the normal signal handler since | |
199 | * we have no guarantee of time of execution of the fill data. | |
200 | */ | |
201 | if (!fSelections.isEmpty()) { | |
3f506e25 JR |
202 | int[] selectionsIndexes = fSelections.stream() |
203 | .map(index -> fPage.getResultTable().getEntries().get(index)) | |
204 | .mapToInt(entry -> ((LamiTableContentProvider) getTableViewer().getContentProvider()).getIndexOf(entry)) | |
205 | .toArray(); | |
206 | ||
4208b510 AM |
207 | Display.getDefault().asyncExec(() -> { |
208 | getTableViewer().getTable().setSelection(selectionsIndexes); | |
209 | getTableViewer().getTable().redraw(); | |
210 | }); | |
211 | } | |
682c435f GAPG |
212 | if (!fSelection.isEmpty()) { |
213 | LamiTableContentProvider provider = (LamiTableContentProvider) getTableViewer().getContentProvider(); | |
214 | ||
215 | /* Find the indexes in the UI table of the selected objects */ | |
216 | int[] selectionsIndexes = fSelection.stream() | |
217 | .map(obj -> (LamiTableEntry) obj) | |
218 | .mapToInt(entry -> provider.getIndexOf(checkNotNull(entry))) | |
219 | .toArray(); | |
220 | ||
221 | /* Update the selection in the UI table */ | |
222 | Display.getDefault().asyncExec(() -> { | |
223 | getTableViewer().getTable().setSelection(selectionsIndexes); | |
224 | getTableViewer().getTable().redraw(); | |
225 | }); | |
226 | } | |
4208b510 AM |
227 | }); |
228 | Display.getDefault().asyncExec(() -> { | |
f95c9345 AM |
229 | if (tableViewer.getTable().isDisposed()) { |
230 | return; | |
231 | } | |
232 | ||
4208b510 AM |
233 | TableColumn[] cols = tableViewer.getTable().getColumns(); |
234 | for (int i = 0; i < cols.length; i++) { | |
235 | cols[i].pack(); | |
236 | } | |
237 | }); | |
238 | } | |
239 | ||
682c435f GAPG |
240 | // ------------------------------------------------------------------------ |
241 | // Signals | |
242 | // ------------------------------------------------------------------------ | |
243 | ||
4208b510 AM |
244 | /** |
245 | * The signal handler for selection update. | |
246 | * | |
247 | * @param signal | |
248 | * The selection update signal | |
249 | */ | |
250 | @TmfSignalHandler | |
251 | public void updateSelection(LamiSelectionUpdateSignal signal) { | |
252 | ||
3f506e25 | 253 | if (fPage != signal.getSignalKey() || equals(signal.getSource())) { |
4208b510 AM |
254 | /* The signal is not for us */ |
255 | return; | |
256 | } | |
257 | /* Fetch the position of the selected entry in the actual table since it could be sorted by another column */ | |
258 | LamiTableContentProvider latencyContentProvider = (LamiTableContentProvider) getTableViewer().getContentProvider(); | |
259 | ||
260 | Set<Integer> selections = signal.getEntryIndex(); | |
261 | ||
262 | int[] selectionsIndexes = selections.stream() | |
3f506e25 | 263 | .map(index -> fPage.getResultTable().getEntries().get(index)) |
4208b510 AM |
264 | .mapToInt(entry -> latencyContentProvider.getIndexOf(entry)) |
265 | .toArray(); | |
266 | ||
267 | fSelections = new HashSet<>(selections); | |
268 | ||
269 | Display.getDefault().asyncExec(() -> { | |
270 | getTableViewer().getTable().setSelection(selectionsIndexes); | |
271 | getTableViewer().getTable().redraw(); | |
272 | }); | |
273 | } | |
682c435f GAPG |
274 | |
275 | /** | |
276 | * The signal handler for selection update. | |
277 | * | |
278 | * @param signal | |
279 | * The selection update signal | |
280 | */ | |
281 | @TmfSignalHandler | |
282 | public void updateCustomSelection(ChartSelectionUpdateSignal signal) { | |
283 | /* Make sure we are not sending a signal to ourself */ | |
284 | if (signal.getSource() == this) { | |
285 | return; | |
286 | } | |
287 | ||
288 | /* Make sure the signal comes from the data provider's scope */ | |
289 | if (fPage.getResultTable().hashCode() != signal.getDataProvider().hashCode()) { | |
290 | return; | |
291 | } | |
292 | ||
293 | /* Get the set of selected objects */ | |
294 | fSelection = signal.getSelectedObject(); | |
295 | ||
296 | /* Get the selected index in the UI table */ | |
297 | LamiTableContentProvider tableContentProvider = (LamiTableContentProvider) getTableViewer().getContentProvider(); | |
298 | int[] tableSelection = fSelection.stream() | |
299 | .map(obj -> (LamiTableEntry) obj) | |
300 | .mapToInt(entry -> tableContentProvider.getIndexOf(checkNotNull(entry))) | |
301 | .toArray(); | |
302 | ||
303 | /* Update the selection in the UI table */ | |
304 | Display.getDefault().asyncExec(() -> { | |
305 | getTableViewer().getTable().setSelection(tableSelection); | |
306 | getTableViewer().getTable().redraw(); | |
307 | }); | |
308 | } | |
309 | ||
4208b510 | 310 | } |