Commit | Line | Data |
---|---|---|
7692e512 AM |
1 | /******************************************************************************* |
2 | * Copyright (c) 2013 École Polytechnique de Montréal, 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 | * Florian Wininger - Initial API and implementation | |
11 | * Alexandre Montplaisir - Refactoring, performance tweaks | |
fec1ac0b | 12 | * Bernd Hufmann - Updated signal handling |
7692e512 AM |
13 | *******************************************************************************/ |
14 | ||
15 | package org.eclipse.linuxtools.tmf.ui.views.statesystem; | |
16 | ||
278aa247 | 17 | import java.io.File; |
7692e512 AM |
18 | import java.util.LinkedHashMap; |
19 | import java.util.List; | |
20 | import java.util.Map; | |
21 | ||
278aa247 FW |
22 | import org.eclipse.jface.action.Action; |
23 | import org.eclipse.jface.action.IToolBarManager; | |
24 | import org.eclipse.jface.resource.ImageDescriptor; | |
25 | import org.eclipse.linuxtools.internal.tmf.ui.Activator; | |
7692e512 AM |
26 | import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; |
27 | import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; | |
28 | import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException; | |
29 | import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; | |
30 | import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; | |
31 | import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler; | |
32 | import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal; | |
33 | import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal; | |
fec1ac0b | 34 | import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal; |
7692e512 AM |
35 | import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal; |
36 | import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; | |
37 | import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue; | |
38 | import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; | |
39 | import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; | |
40 | import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; | |
b9a5bf8f | 41 | import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager; |
7692e512 AM |
42 | import org.eclipse.linuxtools.tmf.ui.views.TmfView; |
43 | import org.eclipse.swt.SWT; | |
278aa247 | 44 | import org.eclipse.swt.graphics.Image; |
7692e512 | 45 | import org.eclipse.swt.widgets.Composite; |
278aa247 | 46 | import org.eclipse.swt.widgets.Display; |
7692e512 AM |
47 | import org.eclipse.swt.widgets.Event; |
48 | import org.eclipse.swt.widgets.Listener; | |
49 | import org.eclipse.swt.widgets.Tree; | |
50 | import org.eclipse.swt.widgets.TreeColumn; | |
51 | import org.eclipse.swt.widgets.TreeItem; | |
278aa247 | 52 | import org.eclipse.ui.IActionBars; |
7692e512 AM |
53 | |
54 | /** | |
55 | * Displays the State System at a current time. | |
56 | * | |
57 | * @author Florian Wininger | |
58 | * @author Alexandre Montplaisir | |
59 | * @since 2.0 | |
60 | */ | |
61 | public class TmfStateSystemExplorer extends TmfView { | |
62 | ||
63 | /** The Environment View's ID */ | |
64 | public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.ssview"; //$NON-NLS-1$ | |
65 | ||
66 | private static final String emptyString = ""; //$NON-NLS-1$ | |
278aa247 FW |
67 | private static final String FS = File.separator; |
68 | private static final Image FILTER_IMAGE = | |
69 | Activator.getDefault().getImageFromPath(FS + "icons" + FS + "elcl16" + FS + "filter_items.gif"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
7692e512 AM |
70 | |
71 | /* Order of columns */ | |
72 | private static final int ATTRIBUTE_NAME_COL = 0; | |
73 | private static final int QUARK_COL = 1; | |
74 | private static final int VALUE_COL = 2; | |
278aa247 FW |
75 | private static final int TYPE_COL = 3; |
76 | private static final int START_TIME_COL = 4; | |
77 | private static final int END_TIME_COL = 5; | |
78 | private static final int ATTRIBUTE_FULLPATH_COL = 6; | |
7692e512 AM |
79 | |
80 | private ITmfTrace fTrace; | |
81 | private Tree fTree; | |
82 | private volatile long fCurrentTimestamp = -1L; | |
83 | ||
278aa247 FW |
84 | private boolean filterStatus = false ; |
85 | ||
7692e512 AM |
86 | /** |
87 | * Default constructor | |
88 | */ | |
89 | public TmfStateSystemExplorer() { | |
90 | super(ID); | |
91 | } | |
92 | ||
93 | // ------------------------------------------------------------------------ | |
94 | // ViewPart | |
95 | // ------------------------------------------------------------------------ | |
96 | ||
97 | @Override | |
98 | public void createPartControl(Composite parent) { | |
99 | fTree = new Tree(parent, SWT.NONE); | |
100 | TreeColumn nameCol = new TreeColumn(fTree, SWT.NONE, ATTRIBUTE_NAME_COL); | |
101 | TreeColumn quarkCol = new TreeColumn(fTree, SWT.NONE, QUARK_COL); | |
102 | TreeColumn valueCol = new TreeColumn(fTree, SWT.NONE, VALUE_COL); | |
278aa247 | 103 | TreeColumn typeCol = new TreeColumn(fTree, SWT.NONE, TYPE_COL); |
7692e512 AM |
104 | TreeColumn startCol = new TreeColumn(fTree, SWT.NONE, START_TIME_COL); |
105 | TreeColumn endCol = new TreeColumn(fTree, SWT.NONE, END_TIME_COL); | |
106 | TreeColumn pathCol = new TreeColumn(fTree, SWT.NONE, ATTRIBUTE_FULLPATH_COL); | |
107 | ||
108 | nameCol.setText(Messages.TreeNodeColumnLabel); | |
109 | quarkCol.setText(Messages.QuarkColumnLabel); | |
110 | valueCol.setText(Messages.ValueColumnLabel); | |
278aa247 | 111 | typeCol.setText(Messages.TypeColumnLabel); |
7692e512 AM |
112 | startCol.setText(Messages.StartTimeColumLabel); |
113 | endCol.setText(Messages.EndTimeColumLabel); | |
114 | pathCol.setText(Messages.AttributePathColumnLabel); | |
115 | ||
116 | fTree.setItemCount(0); | |
117 | ||
118 | fTree.setHeaderVisible(true); | |
119 | nameCol.pack(); | |
120 | valueCol.pack(); | |
121 | ||
122 | fTree.addListener(SWT.Expand, new Listener() { | |
123 | @Override | |
124 | public void handleEvent(Event e) { | |
125 | TreeItem item = (TreeItem) e.item; | |
126 | item.setExpanded(true); | |
127 | updateTable(); | |
128 | } | |
129 | }); | |
130 | ||
131 | ITmfTrace trace = getActiveTrace(); | |
132 | if (trace != null) { | |
133 | traceSelected(new TmfTraceSelectedSignal(this, trace)); | |
134 | } | |
278aa247 FW |
135 | |
136 | fillToolBar() ; | |
137 | ||
7692e512 AM |
138 | } |
139 | ||
140 | // ------------------------------------------------------------------------ | |
141 | // Operations | |
142 | // ------------------------------------------------------------------------ | |
143 | ||
144 | /** | |
145 | * Create the initial tree from a trace. | |
146 | */ | |
147 | private synchronized void createTable() { | |
278aa247 FW |
148 | |
149 | long ts = fCurrentTimestamp; | |
150 | ||
7692e512 AM |
151 | if (fTrace == null) { |
152 | return; | |
153 | } | |
154 | ||
155 | /* Clear the table, in case a trace was previously using it */ | |
156 | fTree.getDisplay().asyncExec(new Runnable() { | |
157 | @Override | |
158 | public void run() { | |
159 | fTree.setItemCount(0); | |
160 | } | |
161 | }); | |
162 | ||
b9a5bf8f | 163 | for (final ITmfTrace currentTrace : TmfTraceManager.getTraceSet(fTrace)) { |
7692e512 AM |
164 | /* |
165 | * We will first do all the queries for this trace, then update that | |
166 | * sub-tree in the UI thread. | |
167 | */ | |
168 | final Map<String, ITmfStateSystem> sss = currentTrace.getStateSystems(); | |
169 | final Map<String, List<ITmfStateInterval>> fullStates = | |
170 | new LinkedHashMap<String, List<ITmfStateInterval>>(); | |
171 | for (Map.Entry<String, ITmfStateSystem> entry : sss.entrySet()) { | |
172 | String ssName = entry.getKey(); | |
173 | ITmfStateSystem ss = entry.getValue(); | |
174 | ss.waitUntilBuilt(); | |
278aa247 FW |
175 | if (ts == -1 || ts < ss.getStartTime() || ts > ss.getCurrentEndTime()) { |
176 | ts = ss.getStartTime(); | |
177 | } | |
7692e512 | 178 | try { |
278aa247 | 179 | fullStates.put(ssName, ss.queryFullState(ts)); |
7692e512 | 180 | } catch (TimeRangeException e) { |
278aa247 | 181 | /* We already checked the limits ourselves */ |
7692e512 AM |
182 | throw new RuntimeException(); |
183 | } catch (StateSystemDisposedException e) { | |
184 | /* Probably shutting down, cancel and return */ | |
185 | return; | |
186 | } | |
187 | } | |
188 | ||
189 | /* Update the table (in the UI thread) */ | |
190 | fTree.getDisplay().asyncExec(new Runnable() { | |
191 | @Override | |
192 | public void run() { | |
193 | TreeItem traceRoot = new TreeItem(fTree, SWT.NONE); | |
194 | traceRoot.setText(ATTRIBUTE_NAME_COL, currentTrace.getName()); | |
195 | ||
196 | for (Map.Entry<String, ITmfStateSystem> entry : sss.entrySet()) { | |
197 | String ssName = entry.getKey(); | |
198 | ITmfStateSystem ss = entry.getValue(); | |
199 | List<ITmfStateInterval> fullState = fullStates.get(ssName); | |
200 | ||
201 | /* Root item of the current state system */ | |
202 | TreeItem item = new TreeItem(traceRoot, SWT.NONE); | |
203 | ||
204 | /* Name of the SS goes in the first column */ | |
205 | item.setText(ATTRIBUTE_NAME_COL, ssName); | |
206 | ||
207 | /* | |
208 | * Calling with quark '-1' here to start with the root | |
209 | * attribute, then it will be called recursively. | |
210 | */ | |
211 | addChildren(ss, fullState, -1, item); | |
212 | } | |
213 | ||
214 | /* Expand the first-level tree items */ | |
215 | for (TreeItem item : fTree.getItems()) { | |
216 | item.setExpanded(true); | |
217 | } | |
218 | packColumns(); | |
278aa247 FW |
219 | |
220 | if (filterStatus) { | |
221 | filterChildren(traceRoot); | |
222 | } | |
7692e512 AM |
223 | } |
224 | }); | |
225 | } | |
226 | } | |
227 | ||
228 | /** | |
229 | * Add children node to a newly-created tree. Should only be called by the | |
230 | * UI thread. | |
231 | */ | |
232 | private void addChildren(ITmfStateSystem ss, | |
233 | List<ITmfStateInterval> fullState, int rootQuark, TreeItem root) { | |
234 | try { | |
235 | for (int quark : ss.getSubAttributes(rootQuark, false)) { | |
236 | TreeItem subItem = new TreeItem(root, SWT.NONE); | |
237 | ||
238 | /* Write the info we already know */ | |
239 | subItem.setText(ATTRIBUTE_NAME_COL, ss.getAttributeName(quark)); | |
240 | subItem.setText(QUARK_COL, String.valueOf(quark)); | |
241 | subItem.setText(ATTRIBUTE_FULLPATH_COL, ss.getFullAttributePath(quark)); | |
242 | ||
243 | /* Populate the other columns */ | |
244 | ITmfStateInterval interval = fullState.get(quark); | |
245 | populateColumns(subItem, interval); | |
246 | ||
247 | /* Update this node's children recursively */ | |
248 | addChildren(ss, fullState, quark, subItem); | |
249 | } | |
250 | ||
251 | } catch (AttributeNotFoundException e) { | |
252 | /* Should not happen, we're iterating on known attributes */ | |
253 | throw new RuntimeException(); | |
254 | } | |
255 | } | |
256 | ||
257 | /** | |
258 | * Update the tree, which means keep the tree of attributes in the first | |
259 | * column as-is, but update the values to the ones at a new timestamp. | |
260 | */ | |
261 | private synchronized void updateTable() { | |
b9a5bf8f | 262 | ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace); |
7692e512 AM |
263 | long ts = fCurrentTimestamp; |
264 | ||
265 | /* For each trace... */ | |
266 | for (int traceNb = 0; traceNb < traces.length; traceNb++) { | |
267 | Map<String, ITmfStateSystem> sss = traces[traceNb].getStateSystems(); | |
268 | ||
269 | /* For each state system associated with this trace... */ | |
270 | int ssNb = 0; | |
271 | for (Map.Entry<String, ITmfStateSystem> entry : sss.entrySet()) { | |
272 | /* | |
273 | * Even though we only use the value, it just feels safer to | |
274 | * iterate the same way as before to keep the order the same. | |
275 | */ | |
276 | final ITmfStateSystem ss = entry.getValue(); | |
277 | final int traceNb1 = traceNb; | |
278 | final int ssNb1 = ssNb; | |
279 | ts = (ts == -1 ? ss.getStartTime() : ts); | |
280 | try { | |
281 | final List<ITmfStateInterval> fullState = ss.queryFullState(ts); | |
282 | fTree.getDisplay().asyncExec(new Runnable() { | |
283 | @Override | |
284 | public void run() { | |
285 | /* Get the tree item of the relevant state system */ | |
286 | TreeItem traceItem = fTree.getItem(traceNb1); | |
287 | TreeItem item = traceItem.getItem(ssNb1); | |
288 | /* Update it, then its children, recursively */ | |
289 | item.setText(VALUE_COL, emptyString); | |
290 | updateChildren(ss, fullState, -1, item); | |
291 | } | |
292 | }); | |
293 | ||
294 | } catch (TimeRangeException e) { | |
295 | /* | |
296 | * This can happen in an experiment, if the user selects a | |
297 | * range valid in the experiment, but this specific does not | |
298 | * exist. Print "out-of-range" into all the values. | |
299 | */ | |
300 | fTree.getDisplay().asyncExec(new Runnable() { | |
301 | @Override | |
302 | public void run() { | |
303 | TreeItem traceItem = fTree.getItem(traceNb1); | |
304 | TreeItem item = traceItem.getItem(ssNb1); | |
305 | markOutOfRange(item); | |
306 | } | |
307 | }); | |
308 | } catch (StateSystemDisposedException e) { | |
309 | return; | |
310 | } | |
311 | ||
312 | ssNb++; | |
313 | } | |
314 | } | |
315 | } | |
316 | ||
317 | /** | |
318 | * Update the values shown by a child row when doing an update. Should only | |
319 | * be called by the UI thread. | |
320 | */ | |
321 | private void updateChildren(ITmfStateSystem ss, | |
322 | List<ITmfStateInterval> state, int root_quark, TreeItem root) { | |
323 | try { | |
324 | for (TreeItem item : root.getItems()) { | |
325 | int quark = ss.getQuarkRelative(root_quark, item.getText(0)); | |
326 | ITmfStateInterval interval = state.get(quark); | |
327 | populateColumns(item, interval); | |
328 | ||
329 | /* Update children recursively */ | |
330 | updateChildren(ss, state, quark, item); | |
331 | } | |
332 | ||
333 | } catch (AttributeNotFoundException e) { | |
334 | /* We're iterating on known attributes, should not happen */ | |
335 | throw new RuntimeException(); | |
336 | } | |
337 | } | |
338 | ||
339 | /** | |
340 | * Populate an 'item' (a row in the tree) with the information found in the | |
341 | * interval. This method should only be called by the UI thread. | |
342 | */ | |
278aa247 | 343 | private void populateColumns(TreeItem item, ITmfStateInterval interval) { |
7692e512 AM |
344 | try { |
345 | ITmfStateValue state = interval.getStateValue(); | |
278aa247 | 346 | String value ; |
7692e512 AM |
347 | |
348 | // add the value in the 2nd column | |
349 | switch (state.getType()) { | |
350 | case INTEGER: | |
278aa247 FW |
351 | value = String.valueOf(state.unboxInt()); |
352 | item.setText(TYPE_COL, Messages.TypeInteger); | |
7692e512 AM |
353 | break; |
354 | case LONG: | |
278aa247 FW |
355 | value = String.valueOf(state.unboxLong()); |
356 | item.setText(TYPE_COL, Messages.TypeLong); | |
7692e512 AM |
357 | break; |
358 | case STRING: | |
278aa247 FW |
359 | value = state.unboxStr(); |
360 | item.setText(TYPE_COL, Messages.TypeString); | |
7692e512 AM |
361 | break; |
362 | case NULL: | |
363 | default: | |
278aa247 FW |
364 | value = emptyString ; |
365 | item.setText(TYPE_COL, emptyString); | |
7692e512 AM |
366 | break; |
367 | } | |
368 | ||
369 | TmfTimestamp startTime = new TmfTimestamp(interval.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE); | |
370 | item.setText(START_TIME_COL, startTime.toString()); | |
371 | ||
372 | TmfTimestamp endTime = new TmfTimestamp(interval.getEndTime(), ITmfTimestamp.NANOSECOND_SCALE); | |
373 | item.setText(END_TIME_COL, endTime.toString()); | |
374 | ||
278aa247 FW |
375 | item.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)) ; |
376 | ||
31d773ed | 377 | if (!filterStatus && (!value.equals(item.getText(VALUE_COL)) || fCurrentTimestamp == startTime.getValue())) { |
278aa247 | 378 | item.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_YELLOW)); |
278aa247 FW |
379 | } |
380 | ||
381 | item.setText(VALUE_COL, value) ; | |
382 | ||
7692e512 AM |
383 | } catch (StateValueTypeException e) { |
384 | /* Should not happen, we're case-switching on the specific types */ | |
385 | throw new RuntimeException(); | |
386 | } | |
387 | } | |
388 | ||
389 | /** | |
390 | * Same concept as {@link updateChildren}, but instead of printing actual | |
391 | * values coming from the state system, we print "Out of range" into all | |
392 | * values. This is to indicate that this specific state system is not | |
393 | * currently defined at the selected timestamp. | |
394 | * | |
395 | * Guess by which thread this should be called? Hint: starts with a U, ends | |
396 | * with an I. | |
397 | */ | |
398 | private void markOutOfRange(TreeItem root) { | |
399 | root.setText(VALUE_COL, Messages.OutOfRangeMsg); | |
278aa247 | 400 | root.setText(TYPE_COL, emptyString); |
7692e512 AM |
401 | root.setText(START_TIME_COL, emptyString); |
402 | root.setText(END_TIME_COL, emptyString); | |
403 | for (TreeItem item : root.getItems()) { | |
404 | markOutOfRange(item); | |
405 | } | |
406 | } | |
407 | ||
408 | /** | |
409 | * Auto-pack all the columns in the display. Should only be called by the UI | |
410 | * thread. | |
411 | */ | |
412 | private void packColumns() { | |
413 | //FIXME should add a bit of padding | |
414 | for (TreeColumn column : fTree.getColumns()) { | |
415 | column.pack(); | |
416 | } | |
417 | } | |
418 | ||
419 | @Override | |
420 | public void setFocus() { | |
421 | fTree.setFocus(); | |
422 | } | |
423 | ||
424 | // ------------------------------------------------------------------------ | |
425 | // Signal handlers | |
426 | // ------------------------------------------------------------------------ | |
fec1ac0b BH |
427 | /** |
428 | * Handler for the trace opened signal. | |
429 | * @param signal | |
430 | * The incoming signal | |
431 | * @since 2.0 | |
432 | */ | |
433 | @TmfSignalHandler | |
434 | public void traceOpened(TmfTraceOpenedSignal signal) { | |
435 | fTrace = signal.getTrace(); | |
436 | loadTrace(); | |
437 | } | |
7692e512 AM |
438 | |
439 | /** | |
440 | * Handler for the trace selected signal. This will make the view display | |
441 | * the information for the newly-selected trace. | |
442 | * | |
443 | * @param signal | |
444 | * The incoming signal | |
445 | */ | |
446 | @TmfSignalHandler | |
447 | public void traceSelected(TmfTraceSelectedSignal signal) { | |
448 | ITmfTrace trace = signal.getTrace(); | |
449 | if (trace != fTrace) { | |
450 | fTrace = trace; | |
fec1ac0b | 451 | loadTrace(); |
7692e512 AM |
452 | } |
453 | } | |
454 | ||
455 | /** | |
456 | * Handler for the trace closed signal. This will clear the view. | |
457 | * | |
458 | * @param signal | |
459 | * the incoming signal | |
460 | */ | |
461 | @TmfSignalHandler | |
462 | public void traceClosed(TmfTraceClosedSignal signal) { | |
463 | // delete the tree at the trace closed | |
464 | if (signal.getTrace() == fTrace) { | |
465 | fTrace = null; | |
466 | fTree.setItemCount(0); | |
467 | } | |
468 | } | |
469 | ||
470 | /** | |
471 | * Handles the current time updated signal. This will update the view's | |
472 | * values to the newly-selected timestamp. | |
473 | * | |
474 | * @param signal | |
475 | * the signal to process | |
476 | */ | |
477 | @TmfSignalHandler | |
478 | public void currentTimeUpdated(final TmfTimeSynchSignal signal) { | |
479 | Thread thread = new Thread("State system visualizer update") { //$NON-NLS-1$ | |
480 | @Override | |
481 | public void run() { | |
482 | ITmfTimestamp currentTime = signal.getCurrentTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE); | |
483 | fCurrentTimestamp = currentTime.getValue(); | |
278aa247 FW |
484 | |
485 | if (filterStatus) { | |
486 | createTable(); | |
487 | } else { | |
488 | updateTable(); | |
489 | } | |
7692e512 AM |
490 | } |
491 | }; | |
492 | thread.start(); | |
493 | } | |
fec1ac0b BH |
494 | |
495 | private void loadTrace() { | |
496 | Thread thread = new Thread("State system visualizer construction") { //$NON-NLS-1$ | |
497 | @Override | |
498 | public void run() { | |
499 | createTable(); | |
500 | } | |
501 | }; | |
502 | thread.start(); | |
503 | } | |
504 | ||
278aa247 FW |
505 | /** |
506 | * Function for the delete TreeItem | |
507 | */ | |
508 | private boolean filterChildren(TreeItem root) { | |
509 | boolean valid = false ; | |
510 | TmfTimestamp startTime = new TmfTimestamp(fCurrentTimestamp, ITmfTimestamp.NANOSECOND_SCALE); | |
511 | valid = root.getText(START_TIME_COL).equals(startTime.toString()); | |
512 | root.setExpanded(true); | |
513 | ||
514 | for (TreeItem item : root.getItems()) { | |
515 | /* Update children recursively */ | |
516 | valid = filterChildren(item) || valid; | |
517 | } | |
518 | ||
519 | if (!valid) { | |
520 | root.dispose(); | |
521 | } | |
522 | return valid; | |
523 | } | |
524 | ||
525 | // ------------------------------------------------------------------------ | |
526 | // Part For Button Action | |
527 | // ------------------------------------------------------------------------ | |
528 | ||
529 | ||
530 | ||
531 | private void fillToolBar() { | |
532 | Action fFilterAction = new FilterAction(); | |
533 | fFilterAction.setImageDescriptor(ImageDescriptor.createFromImage(FILTER_IMAGE)); | |
534 | fFilterAction.setToolTipText(Messages.FilterButton) ; | |
535 | fFilterAction.setChecked(false); | |
536 | ||
537 | IActionBars bars = getViewSite().getActionBars(); | |
538 | IToolBarManager manager = bars.getToolBarManager(); | |
539 | manager.add(fFilterAction); | |
540 | } | |
541 | ||
542 | private class FilterAction extends Action { | |
543 | @Override | |
544 | public void run() { | |
545 | filterStatus = !filterStatus; | |
546 | if (!filterStatus) { | |
547 | createTable(); | |
548 | } | |
549 | } | |
550 | } | |
7692e512 | 551 | } |