tmf: log when an error message is displayed in a MessageBox
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / rawviewer / TmfRawEventViewer.java
CommitLineData
7d048a33 1/*******************************************************************************
812e7197 2 * Copyright (c) 2010, 2015 Ericsson
7d048a33
PT
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 * Patrick Tasse - Initial API and implementation
11 ******************************************************************************/
12
2bdf0193 13package org.eclipse.tracecompass.tmf.ui.widgets.rawviewer;
7d048a33
PT
14
15import java.util.ArrayList;
16import java.util.List;
17
332c750a 18import org.eclipse.jface.resource.ColorRegistry;
812e7197
PT
19import org.eclipse.jface.resource.FontRegistry;
20import org.eclipse.jface.util.IPropertyChangeListener;
21import org.eclipse.jface.util.PropertyChangeEvent;
7d048a33
PT
22import org.eclipse.swt.SWT;
23import org.eclipse.swt.custom.CaretEvent;
24import org.eclipse.swt.custom.CaretListener;
25import org.eclipse.swt.custom.ScrolledComposite;
26import org.eclipse.swt.custom.StyledText;
27import org.eclipse.swt.events.ControlEvent;
28import org.eclipse.swt.events.ControlListener;
29import org.eclipse.swt.events.KeyEvent;
30import org.eclipse.swt.events.KeyListener;
31import org.eclipse.swt.events.MouseAdapter;
32import org.eclipse.swt.events.MouseEvent;
29ddb729 33import org.eclipse.swt.events.MouseListener;
7d048a33
PT
34import org.eclipse.swt.events.MouseMoveListener;
35import org.eclipse.swt.events.MouseTrackListener;
36import org.eclipse.swt.events.MouseWheelListener;
37import org.eclipse.swt.events.SelectionEvent;
38import org.eclipse.swt.events.SelectionListener;
39import org.eclipse.swt.graphics.Color;
40import org.eclipse.swt.graphics.Font;
7d048a33
PT
41import org.eclipse.swt.graphics.Point;
42import org.eclipse.swt.layout.GridData;
43import org.eclipse.swt.layout.GridLayout;
44import org.eclipse.swt.widgets.Composite;
45import org.eclipse.swt.widgets.Control;
46import org.eclipse.swt.widgets.Display;
47import org.eclipse.swt.widgets.Event;
48import org.eclipse.swt.widgets.Listener;
49import org.eclipse.swt.widgets.Menu;
50import org.eclipse.swt.widgets.Slider;
2bdf0193
AM
51import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
52import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
53import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
54import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
812e7197
PT
55import org.eclipse.ui.PlatformUI;
56import org.eclipse.ui.themes.IThemeManager;
7d048a33
PT
57
58/**
59 * TmfRawEventViewer allows for the display of the raw data for an arbitrarily
60 * large number of TMF events.
61 *
62 * It is essentially a Composite of a StyledText area and a Slider, where the number
63 * of visible lines in the StyledText control is set to fill the viewer display area.
64 * An underlying data model is used to store a cache of event raw text line data.
65 * The slider is ratio-based.
66 *
67 * @version 1.0
68 * @author Patrick Tasse
69 */
29ddb729 70public class TmfRawEventViewer extends Composite implements ControlListener, SelectionListener, MouseListener,
812e7197 71 KeyListener, CaretListener, MouseMoveListener, MouseTrackListener, MouseWheelListener, IPropertyChangeListener {
7d048a33
PT
72
73 private static final Color COLOR_BACKGROUND_ODD = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
74 private static final Color COLOR_BACKGROUND_EVEN = new Color(Display.getDefault(), 242, 242, 242);
812e7197 75 private static final String FONT_DEFINITION_ID = "org.eclipse.tracecompass.tmf.ui.font.eventraw"; //$NON-NLS-1$
332c750a
PT
76 private static final String HIGHLIGHT_COLOR_DEFINITION_ID = "org.eclipse.tracecompass.tmf.ui.color.eventraw.highlight"; //$NON-NLS-1$
77 private static final String SELECTION_COLOR_DEFINITION_ID = "org.eclipse.tracecompass.tmf.ui.color.eventraw.selection"; //$NON-NLS-1$
7d048a33
PT
78 private static final int MAX_LINE_DATA_SIZE = 1000;
79 private static final int SLIDER_MAX = 1000000;
80
81 private ITmfTrace fTrace;
82 private ITmfContext fBottomContext;
83
84 private ScrolledComposite fScrolledComposite;
85 private Composite fTextArea;
86 private StyledText fStyledText;
87 private Font fFixedFont;
332c750a
PT
88 private Color fHighlightColor;
89 private Color fSelectionColor;
d5efe032 90 private Slider fSlider;
29ddb729 91 private SliderThrottler fSliderThrottler;
d5efe032
AF
92
93 private final List<LineData> fLines = new ArrayList<>();
94 private boolean fActualRanks = false;
95 private int fTopLineIndex;
96 private int fLastTopLineIndex;
97 private final CaretPosition[] fStoredCaretPosition = new CaretPosition[]
98 { new CaretPosition(0, 0), new CaretPosition(0,0)};
99 private int fNumVisibleLines;
7d048a33
PT
100 private ITmfLocation fSelectedLocation = null;
101 private long fHighlightedRank = Long.MIN_VALUE;
102 private int fCursorYCoordinate = -1;
103 private int fHoldSelection = 0;
104
29ddb729
PT
105 // ------------------------------------------------------------------------
106 // Classes
107 // ------------------------------------------------------------------------
108
d5efe032
AF
109 private static class LineData {
110 long rank;
111 ITmfLocation location;
112 String string;
113 public LineData(long rank, ITmfLocation location, String string) {
114 this.rank = rank;
115 this.location = location;
7d048a33
PT
116 if (string.length() == 0) {
117 this.string = " "; // workaround for setLineBackground has no effect on empty line //$NON-NLS-1$
118 } else {
119 this.string = string;
120 }
d5efe032 121 }
7d048a33
PT
122 @Override
123 public String toString() {
124 return rank + " [" + location + "]: " + string; //$NON-NLS-1$ //$NON-NLS-2$
125 }
d5efe032
AF
126 }
127
128 private static class CaretPosition {
129 int time;
130 int caretOffset;
131 public CaretPosition(int time, int caretOffset) {
132 this.time = time;
133 this.caretOffset = caretOffset;
134 }
135 }
136
29ddb729
PT
137 private class SliderThrottler extends Thread {
138 private static final long DELAY = 400L;
139 private static final long POLLING_INTERVAL = 10L;
140
141 @Override
142 public void run() {
143 final long startTime = System.currentTimeMillis();
144 while ((System.currentTimeMillis() - startTime) < DELAY) {
145 try {
146 Thread.sleep(POLLING_INTERVAL);
147 } catch (InterruptedException e) {
148 }
149 }
150 Display.getDefault().asyncExec(new Runnable() {
151 @Override
152 public void run() {
153 if (fSliderThrottler != SliderThrottler.this) {
154 return;
155 }
156 fSliderThrottler = null;
157 if (SliderThrottler.this.isInterrupted() || fSlider.isDisposed()) {
158 return;
159 }
160 Event event = new Event();
161 event.widget = TmfRawEventViewer.this;
162 event.detail = SWT.NONE;
163 widgetSelected(new SelectionEvent(event));
164 }
165 });
166 }
167 }
168
d5efe032
AF
169 // ------------------------------------------------------------------------
170 // Constructor
171 // ------------------------------------------------------------------------
172
173 /**
174 * Constructor
175 * @param parent The parent composite
176 * @param style The style bits
177 */
178 public TmfRawEventViewer(Composite parent, int style) {
179 super(parent, style & (~SWT.H_SCROLL) & (~SWT.V_SCROLL));
180
181 // Set the layout
182 GridLayout gridLayout = new GridLayout();
183 gridLayout.numColumns = 2;
184 gridLayout.horizontalSpacing = 0;
185 gridLayout.verticalSpacing = 0;
7d048a33
PT
186 gridLayout.marginWidth = 0;
187 gridLayout.marginHeight = 0;
d5efe032 188 setLayout(gridLayout);
7d048a33 189
d5efe032
AF
190 // Create the controls
191 createTextArea(style & SWT.H_SCROLL);
192 createSlider(style & SWT.V_SCROLL);
7d048a33 193
d5efe032
AF
194 // Prevent the slider from being traversed
195 setTabList(new Control[] { fScrolledComposite });
196 }
7d048a33
PT
197
198 @Override
d5efe032 199 public void dispose() {
e5f3e782
PT
200 if (fBottomContext != null) {
201 fBottomContext.dispose();
202 }
812e7197 203 PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(this);
d5efe032
AF
204 super.dispose();
205 }
7d048a33 206
812e7197 207 // ------------------------------------------------------------------------
332c750a 208 // Font and color handling
812e7197
PT
209 // ------------------------------------------------------------------------
210
211 /**
212 * Initialize the fonts.
213 * @since 1.0
214 */
215 protected void initializeFonts() {
216 FontRegistry fontRegistry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getFontRegistry();
217 fFixedFont = fontRegistry.get(FONT_DEFINITION_ID);
218 fStyledText.setFont(fFixedFont);
219 }
220
332c750a
PT
221 /**
222 * Initialize the colors.
0336f981 223 * @since 1.1
332c750a
PT
224 */
225 protected void initializeColors() {
226 ColorRegistry colorRegistry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry();
227 fHighlightColor = colorRegistry.get(HIGHLIGHT_COLOR_DEFINITION_ID);
228 fSelectionColor = colorRegistry.get(SELECTION_COLOR_DEFINITION_ID);
229 }
230
812e7197
PT
231 /**
232 * @since 1.0
233 */
234 @Override
235 public void propertyChange(PropertyChangeEvent event) {
236 if ((IThemeManager.CHANGE_CURRENT_THEME.equals(event.getProperty())) ||
237 (FONT_DEFINITION_ID.equals(event.getProperty()))) {
238 initializeFonts();
239 refreshTextArea();
240 }
332c750a
PT
241 if ((IThemeManager.CHANGE_CURRENT_THEME.equals(event.getProperty())) ||
242 (HIGHLIGHT_COLOR_DEFINITION_ID.equals(event.getProperty())) ||
243 (SELECTION_COLOR_DEFINITION_ID.equals(event.getProperty()))) {
244 initializeColors();
245 refreshTextArea();
246 }
812e7197
PT
247 }
248
d5efe032
AF
249 // ------------------------------------------------------------------------
250 // Text area handling
251 // ------------------------------------------------------------------------
7d048a33
PT
252
253 /**
d5efe032
AF
254 * Create the text area and add listeners
255 */
256 private void createTextArea(int style) {
257 fScrolledComposite = new ScrolledComposite(this, style);
258 fScrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
259 fTextArea = new Composite(fScrolledComposite, SWT.NONE);
7d048a33
PT
260 fTextArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
261 fScrolledComposite.setContent(fTextArea);
262 fScrolledComposite.setExpandHorizontal(true);
263 fScrolledComposite.setExpandVertical(true);
264 fScrolledComposite.setAlwaysShowScrollBars(true);
265 fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
266 fScrolledComposite.addControlListener(this);
267
268 GridLayout textAreaGridLayout = new GridLayout();
269 textAreaGridLayout.marginHeight = 0;
270 textAreaGridLayout.marginWidth = 0;
271 fTextArea.setLayout(textAreaGridLayout);
272
7d048a33 273 fStyledText = new StyledText(fTextArea, SWT.READ_ONLY);
7d048a33
PT
274 fStyledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
275
812e7197 276 initializeFonts();
332c750a 277 initializeColors();
812e7197
PT
278 PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(this);
279
7d048a33
PT
280 fStyledText.addCaretListener(this);
281 fStyledText.addMouseMoveListener(this);
282 fStyledText.addMouseTrackListener(this);
283 fStyledText.addMouseWheelListener(this);
284 fStyledText.addListener(SWT.MouseWheel, new Listener() { // disable mouse scroll of horizontal scroll bar
285 @Override
286 public void handleEvent(Event event) { event.doit = false; }});
287 fStyledText.addKeyListener(this);
288
289 fTextArea.setBackground(fStyledText.getBackground());
290 fTextArea.addMouseListener(new MouseAdapter() {
d5efe032 291 @Override
7d048a33 292 public void mouseDown(MouseEvent e) {
d5efe032 293 fTextArea.setFocus();
7d048a33 294 }});
d5efe032 295 }
7d048a33 296
d5efe032
AF
297 // ------------------------------------------------------------------------
298 // Slider handling
299 // ------------------------------------------------------------------------
7d048a33 300
d5efe032
AF
301 private void createSlider(int style) {
302 fSlider = new Slider(this, SWT.VERTICAL);
7d048a33
PT
303 fSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
304 fSlider.setValues(0, 0, SLIDER_MAX, SLIDER_MAX, 1, 1);
d5efe032 305 fSlider.addSelectionListener(this);
29ddb729 306 fSlider.addMouseListener(this);
7d048a33
PT
307 if ((style & SWT.V_SCROLL) == 0) {
308 fSlider.setVisible(false);
309 }
d5efe032 310 }
7d048a33 311
d5efe032
AF
312 // ------------------------------------------------------------------------
313 // Controls interactions
314 // ------------------------------------------------------------------------
7d048a33 315
d5efe032
AF
316 @Override
317 public boolean setFocus() {
318 boolean isVisible = isVisible();
319 if (isVisible) {
320 fTextArea.setFocus();
321 }
322 return isVisible;
323 }
7d048a33
PT
324
325 @Override
326 public void setMenu(Menu menu) {
327 fStyledText.setMenu(menu);
328 }
329
330 /**
331 * Sets the trace and updates the content
332 * @param trace The trace to set
333 */
334 public void setTrace(ITmfTrace trace) {
d5efe032
AF
335 fTrace = trace;
336 fTopLineIndex = 0;
337 fLines.clear();
338 refreshEventCount();
339 }
7d048a33
PT
340
341 /**
342 * Refreshes the event count, updates the slider thumb and loads display
343 */
d5efe032
AF
344 public void refreshEventCount() {
345 if (fTrace != null) {
346 if (fTrace.getNbEvents() > 0) {
347 fSlider.setThumb((int) Math.max(SLIDER_MAX / fTrace.getNbEvents(), 1));
348 } else {
349 fSlider.setThumb(SLIDER_MAX);
350 }
351
352 if (!isVisible()) {
7d048a33
PT
353 return;
354 }
355
d5efe032
AF
356 if (fLines.size() == 0) {
357 setTopRank(0);
358 } else if (fLines.size() < fNumVisibleLines) {
e5f3e782
PT
359 if (fBottomContext != null) {
360 fBottomContext.dispose();
361 fBottomContext = null;
362 }
d5efe032
AF
363 loadLineData();
364 fillTextArea();
365 //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
366 fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
367 }
7d048a33 368 } else {
e5f3e782
PT
369 if (fBottomContext != null) {
370 fBottomContext.dispose();
371 fBottomContext = null;
372 }
7d048a33
PT
373 fillTextArea();
374 fSlider.setThumb(SLIDER_MAX);
375 fSlider.setSelection(0);
d5efe032
AF
376 }
377 }
7d048a33 378
d5efe032
AF
379 /**
380 * Selects the event of given rank and makes it visible.
381 * @param rank The rank of event
382 */
7d048a33
PT
383 public void selectAndReveal(long rank) {
384 if (fTrace == null || !isVisible()) {
385 return;
386 }
387 if (fActualRanks && fTopLineIndex < fLines.size() && rank >= fLines.get(fTopLineIndex).rank) {
388 int lastVisibleIndex = Math.min(fTopLineIndex + fNumVisibleLines, fLines.size()) - 1;
389 if (rank <= fLines.get(lastVisibleIndex).rank) {
390 for (int i = fTopLineIndex; i < fLines.size(); i++) {
391 if (fLines.get(i).rank == rank) {
392 fSelectedLocation = fLines.get(i).location;
393 break;
394 }
395 }
396 refreshLineBackgrounds();
397 return;
398 }
399 }
400 setTopRank(rank);
401 if (fLines.size() > 0 && fHoldSelection == 0) {
402 fSelectedLocation = fLines.get(0).location;
403 refreshLineBackgrounds();
404 }
405 }
406
407 /**
408 * Add a selection listener
409 * @param listener A listener to add
410 */
411 public void addSelectionListener(Listener listener) {
412 checkWidget();
413 if (listener == null) {
414 SWT.error (SWT.ERROR_NULL_ARGUMENT);
415 }
416 addListener (SWT.Selection, listener);
417 }
418
419 /**
420 * Remove selection listener
421 * @param listener A listener to remove
422 */
423 public void removeSelectionListener(Listener listener) {
424 checkWidget();
425 if (listener == null) {
426 SWT.error (SWT.ERROR_NULL_ARGUMENT);
427 }
428 removeListener(SWT.Selection, listener);
429 }
430
431 private void sendSelectionEvent(LineData lineData) {
432 Event event = new Event();
433 if (fActualRanks) {
434 event.data = Long.valueOf(lineData.rank);
435 } else {
436 event.data = lineData.location;
437 }
438 notifyListeners(SWT.Selection, event);
439 }
440
441 private void setTopRank(long rank) {
e5f3e782
PT
442 if (fBottomContext != null) {
443 fBottomContext.dispose();
444 }
7d048a33
PT
445 fBottomContext = fTrace.seekEvent(rank);
446 if (fBottomContext == null) {
447 return;
448 }
449 fLines.clear();
450 fActualRanks = true;
451 fTopLineIndex = 0;
452 loadLineData();
453 refreshTextArea();
454 if (fLines.size() == 0) {
455 fSlider.setSelection(0);
456 } else {
457 //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
458 fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
459 }
460 }
461
462 private void setTopPosition(double ratio) {
e5f3e782
PT
463 if (fBottomContext != null) {
464 fBottomContext.dispose();
465 }
7d048a33
PT
466 fBottomContext = fTrace.seekEvent(ratio);
467 if (fBottomContext == null) {
468 return;
469 }
470 fBottomContext.setRank(0);
471 fLines.clear();
472 fActualRanks = false;
473 fTopLineIndex = 0;
474 loadLineData();
475 refreshTextArea();
476 }
477
d5efe032 478 private void loadLineData() {
7d048a33
PT
479 if (fTopLineIndex < 0) {
480 //if (fLines.size() > 0 && fLines.get(0).rank > 0) {
481 //long endRank = fLines.get(0).rank;
482 //long startRank = Math.max(0, endRank - fNumVisibleLines);
483 //TmfContext context = fTrace.seekEvent(startRank);
484 //int index = 0;
485 //while (context.getRank() < endRank) {
486 //long rank = context.getRank();
487 //ITmfLocation<?> location = context.getLocation();
488 //TmfEvent event = fTrace.getNextEvent(context);
489 //String[] lines = event.getRawText().split("\r?\n");
490 //for (int i = 0; i < lines.length; i++) {
491 //String line = lines[i];
492 //LineData lineData = new LineData(rank, location, line);
493 //fLines.add(index++, lineData);
494 //fTopLineIndex++;
495 //fLastTopLineIndex++;
496 //}
497 //}
498 //}
499 if (fLines.size() > 0 && fTrace.getLocationRatio(fLines.get(0).location) > 0) {
d5efe032 500 double lastRatio = fTrace.getLocationRatio(fLines.get(fLines.size() - 1).location);
7d048a33
PT
501 double firstRatio = fTrace.getLocationRatio(fLines.get(0).location);
502 double delta;
503 boolean singleEvent = false;
504 if (firstRatio != lastRatio) {
505 // approximate ratio of at least 20 items
506 delta = Math.max(20, fNumVisibleLines) * (lastRatio - firstRatio) / (fLines.size() - 1);
507 } else {
508 delta = Math.pow(10, -15);
509 singleEvent = true;
510 }
511 while (fTopLineIndex < 0) {
512 ITmfLocation endLocation = fLines.get(0).location;
513 firstRatio = Math.max(0, firstRatio - delta);
514 ITmfContext context = fTrace.seekEvent(firstRatio);
515 ITmfLocation location;
516 int index = 0;
517 long rank = 0;
518 while (!context.getLocation().equals(endLocation)) {
519 location = context.getLocation();
520 ITmfEvent event = fTrace.getNext(context);
521 if (event == null) {
d5efe032 522 break;
7d048a33
PT
523 }
524 if (event.getContent() != null && event.getContent().getValue() != null) {
525 String[] lines = event.getContent().getValue().toString().split("\r?\n"); //$NON-NLS-1$
526 for (int i = 0; i < lines.length; i++) {
527 String line = lines[i];
528 LineData lineData = new LineData(rank, location, line);
529 fLines.add(index++, lineData);
530 fTopLineIndex++;
531 fLastTopLineIndex++;
532 }
533 } else {
534 LineData lineData = new LineData(rank, location, ""); //$NON-NLS-1$
535 fLines.add(index++, lineData);
536 fTopLineIndex++;
537 fLastTopLineIndex++;
538 }
539 rank++;
540 }
e5f3e782 541 context.dispose();
7d048a33
PT
542 long rankOffset = fLines.get(index).rank - rank;
543 for (int i = 0; i < index; i++) {
544 fLines.get(i).rank += rankOffset;
545 }
546 if (firstRatio == 0) {
547 break;
548 }
549 if (singleEvent) {
d5efe032 550 delta = Math.min(delta * 10, 0.1);
7d048a33
PT
551 }
552 }
553 }
554 if (fTopLineIndex < 0) {
555 fTopLineIndex = 0;
556 }
557 }
558
d5efe032
AF
559 while (fLines.size() - fTopLineIndex < fNumVisibleLines) {
560 if (fBottomContext == null) {
561 if (fLines.size() == 0) {
562 fBottomContext = fTrace.seekEvent(0);
563 } else {
7d048a33 564 //fBottomContext = fTrace.seekEvent(fLines.get(fLines.size() - 1).rank + 1);
d5efe032
AF
565 fBottomContext = fTrace.seekEvent(fLines.get(fLines.size() - 1).location);
566 fTrace.getNext(fBottomContext);
567 }
568 if (fBottomContext == null) {
569 break;
570 }
571 }
7d048a33
PT
572 long rank = fBottomContext.getRank();
573 ITmfLocation location = fBottomContext.getLocation() != null ? fBottomContext.getLocation() : null;
574 ITmfEvent event = fTrace.getNext(fBottomContext);
575 if (event == null) {
576 break;
577 }
578 if (event.getContent() != null && event.getContent().getValue() != null) {
579 for (String line : event.getContent().getValue().toString().split("\r?\n")) { //$NON-NLS-1$
580 int crPos;
581 if ((crPos = line.indexOf('\r')) != -1) {
d5efe032 582 line = line.substring(0, crPos);
7d048a33
PT
583 }
584 LineData lineData = new LineData(rank, location, line);
585 fLines.add(lineData);
586 }
587 } else {
588 LineData lineData = new LineData(rank, location, ""); //$NON-NLS-1$
589 fLines.add(lineData);
590 }
d5efe032
AF
591 }
592 fTopLineIndex = Math.max(0, Math.min(fTopLineIndex, fLines.size() - 1));
593
594 if (fLines.size() > MAX_LINE_DATA_SIZE) {
595 if (fTopLineIndex < MAX_LINE_DATA_SIZE / 2) {
596 long rank = fLines.get(MAX_LINE_DATA_SIZE - 1).rank;
597 for (int i = MAX_LINE_DATA_SIZE; i < fLines.size(); i++) {
598 if (fLines.get(i).rank > rank) {
599 fLines.subList(i, fLines.size()).clear();
e5f3e782
PT
600 if (fBottomContext != null) {
601 fBottomContext.dispose();
602 fBottomContext = null;
603 }
d5efe032
AF
604 break;
605 }
606 }
607 } else {
608 long rank = fLines.get(fLines.size() - MAX_LINE_DATA_SIZE).rank;
609 for (int i = fLines.size() - MAX_LINE_DATA_SIZE - 1; i >= 0; i--) {
7d048a33
PT
610 if (fLines.get(i).rank < rank) {
611 fLines.subList(0, i + 1).clear();
612 fTopLineIndex -= (i + 1);
613 fLastTopLineIndex -= (i + 1);
614 break;
615 }
d5efe032
AF
616 }
617 }
618 }
619 }
7d048a33
PT
620
621 private void refreshTextArea() {
622 fStyledText.setText(""); //$NON-NLS-1$
623 for (int i = 0; i < fLines.size() - fTopLineIndex && i < fNumVisibleLines; i++) {
624 if (i > 0)
625 {
626 fStyledText.append("\n"); //$NON-NLS-1$
627 }
628 LineData lineData = fLines.get(fTopLineIndex + i);
629 fStyledText.append(lineData.string);
630 setLineBackground(i, lineData);
631 }
632 fTextArea.layout();
633 fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
634 fLastTopLineIndex = fTopLineIndex;
635 }
636
637 private void fillTextArea() {
638 int nextLine = fStyledText.getCharCount() == 0 ? 0 : fStyledText.getLineCount();
639 for (int i = nextLine; i < fLines.size() - fTopLineIndex && i < fNumVisibleLines; i++) {
640 if (i > 0)
641 {
642 fStyledText.append("\n"); //$NON-NLS-1$
643 }
644 LineData lineData = fLines.get(fTopLineIndex + i);
645 fStyledText.append(lineData.string);
646 setLineBackground(i, lineData);
647 }
648 int endLine = Math.min(fNumVisibleLines, fLines.size());
649 if (endLine < fStyledText.getLineCount()) {
d5efe032
AF
650 int endOffset = fStyledText.getOffsetAtLine(endLine) - 1;
651 if (endOffset > fStyledText.getCharCount()) {
7d048a33 652 fHoldSelection++;
d5efe032 653 fStyledText.replaceTextRange(endOffset, fStyledText.getCharCount() - endOffset, ""); //$NON-NLS-1$
7d048a33 654 fHoldSelection--;
d5efe032 655 }
7d048a33
PT
656 }
657 fTextArea.layout();
658 fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
659 }
660
d5efe032
AF
661 private void updateTextArea() {
662 if (fTopLineIndex < fLastTopLineIndex) {
663 StringBuffer insertedText = new StringBuffer();
664 for (int i = fTopLineIndex; i < fLastTopLineIndex; i++) {
665 insertedText.append(fLines.get(i).string + "\n"); //$NON-NLS-1$
666 }
667 fStyledText.replaceTextRange(0, 0, insertedText.toString());
7d048a33
PT
668 for (int i = 0; i < fLastTopLineIndex - fTopLineIndex; i++) {
669 LineData lineData = fLines.get(fTopLineIndex + i);
670 setLineBackground(i, lineData);
671 }
d5efe032
AF
672 fLastTopLineIndex = fTopLineIndex;
673 } else if (fTopLineIndex > fLastTopLineIndex) {
674 int length = 0;
675 for (int i = 0; i < fTopLineIndex - fLastTopLineIndex && i < fNumVisibleLines; i++) {
676 length += fLines.get(i + fLastTopLineIndex).string.length();
677 if (i < fStyledText.getLineCount()) {
7d048a33
PT
678 length += 1;
679 }
d5efe032
AF
680 }
681 fStyledText.replaceTextRange(0, length, ""); //$NON-NLS-1$
7d048a33
PT
682 fLastTopLineIndex = fTopLineIndex;
683 fillTextArea();
d5efe032 684 }
7d048a33
PT
685 int endLine = Math.min(fNumVisibleLines, fLines.size());
686 if (endLine < fStyledText.getLineCount()) {
d5efe032
AF
687 int endOffset = fStyledText.getOffsetAtLine(endLine) - 1;
688 if (endOffset > fStyledText.getCharCount()) {
689 fStyledText.replaceTextRange(endOffset, fStyledText.getCharCount() - endOffset, ""); //$NON-NLS-1$
690 }
7d048a33 691 }
d5efe032
AF
692 fTextArea.layout();
693 fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
694 }
7d048a33 695
d5efe032 696 private void refreshLineBackgrounds() {
7d048a33
PT
697 for (int i = 0; (i < fStyledText.getLineCount()) && (i < fNumVisibleLines) && (i < fLines.size() - fTopLineIndex); i++) {
698 LineData lineData = fLines.get(fTopLineIndex + i);
699 setLineBackground(i, lineData);
700 }
d5efe032 701 }
7d048a33 702
d5efe032 703 private void setLineBackground(int index, LineData lineData) {
7d048a33 704 if (lineData.location.equals(fSelectedLocation)) {
332c750a 705 fStyledText.setLineBackground(index, 1, fSelectionColor);
7d048a33 706 } else if (lineData.rank == fHighlightedRank) {
332c750a 707 fStyledText.setLineBackground(index, 1, fHighlightColor);
7d048a33
PT
708 } else if (lineData.rank % 2 == 0) {
709 fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_EVEN);
710 } else {
711 fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_ODD);
712 }
d5efe032
AF
713 }
714
715 private void storeCaretPosition(int time, int caretOffset) {
716 if (fStoredCaretPosition[0].time == time) {
717 fStoredCaretPosition[0].caretOffset = caretOffset;
718 } else {
719 fStoredCaretPosition[1] = fStoredCaretPosition[0];
720 fStoredCaretPosition[0] = new CaretPosition(time, caretOffset);
721 }
722 }
723
724 private int getPreviousCaretOffset(int time) {
725 if (fStoredCaretPosition[0].time == time) {
726 return fStoredCaretPosition[1].caretOffset;
727 }
7d048a33 728 return fStoredCaretPosition[0].caretOffset;
d5efe032 729 }
7d048a33 730
d5efe032 731 private void updateHighlightedRank() {
7d048a33
PT
732 if (fCursorYCoordinate < 0 || fCursorYCoordinate > fStyledText.getSize().y) {
733 if (fHighlightedRank != Long.MIN_VALUE) {
734 fHighlightedRank = Long.MIN_VALUE;
735 refreshLineBackgrounds();
736 }
737 return;
738 }
739 int offset = fStyledText.getOffsetAtLocation(new Point(0, fCursorYCoordinate));
740 int line = fStyledText.getLineAtOffset(offset);
741 if (line < fLines.size() - fTopLineIndex) {
742 LineData lineData = fLines.get(fTopLineIndex + line);
743 if (fHighlightedRank != lineData.rank) {
744 fHighlightedRank = lineData.rank;
745 refreshLineBackgrounds();
746 }
747 } else {
748 if (fHighlightedRank != Long.MIN_VALUE) {
749 fHighlightedRank = Long.MIN_VALUE;
750 refreshLineBackgrounds();
751 }
752 }
d5efe032 753 }
7d048a33
PT
754
755 // ------------------------------------------------------------------------
756 // ControlListener (ScrolledComposite)
757 // ------------------------------------------------------------------------
758
759 @Override
760 public void controlResized(ControlEvent event) {
761 int areaHeight = fScrolledComposite.getSize().y;
762 if (fScrolledComposite.getHorizontalBar() != null) {
763 areaHeight -= fScrolledComposite.getHorizontalBar().getSize().y;
764 }
765 int lineHeight = fStyledText.getLineHeight();
766 fNumVisibleLines = Math.max((areaHeight + lineHeight - 1) / lineHeight, 1);
767
768 if (fBottomContext != null) {
769 loadLineData();
770 fillTextArea();
771 }
772 }
773
774 @Override
775 public void controlMoved(ControlEvent e) {
776 }
777
778 // ------------------------------------------------------------------------
779 // SelectionListener (Slider)
780 // ------------------------------------------------------------------------
781
782 @Override
783 public void widgetSelected(SelectionEvent e) {
d5efe032 784 fTextArea.setFocus();
7d048a33
PT
785 if (fLines.size() == 0) {
786 return;
787 }
7d048a33
PT
788 fHoldSelection++;
789 switch (e.detail) {
29ddb729 790 case SWT.DRAG:
7d048a33 791 case SWT.NONE: {
29ddb729
PT
792 if (e.widget == fSlider) {
793 /*
794 * While the slider thumb is being dragged, only perform the
795 * refresh periodically. The event detail during the drag is
796 * SWT.DRAG on Windows and SWT.NONE on Linux.
797 */
798 if (fSliderThrottler == null) {
799 fSliderThrottler = new SliderThrottler();
800 fSliderThrottler.start();
801 }
802 fHoldSelection = 0;
803 return;
804 }
805 /*
806 * The selection event was sent by the viewer, refresh now.
807 */
7d048a33
PT
808 //long rank = (long) (fTrace.getNbEvents() * ((double) fSlider.getSelection() / SLIDER_MAX));
809 //setTopRank(rank);
d5efe032 810 if (fSlider.getSelection() == 0 || fSlider.getThumb() == SLIDER_MAX) {
7d048a33
PT
811 fLines.clear();
812 setTopPosition(0.0);
813 break;
d5efe032 814 }
7d048a33
PT
815 double ratio = (double) fSlider.getSelection() / (SLIDER_MAX - fSlider.getThumb());
816 double delta = Math.pow(10, -15);
817 fLines.clear();
818 while (fLines.size() == 0) {
819 setTopPosition(ratio);
820 if (ratio == 0.0) {
821 break;
822 }
823 delta = Math.min(delta * 10, 0.1);
824 ratio = Math.max(ratio - delta, 0.0);
825 }
826 break;
827 }
828 case SWT.ARROW_DOWN: {
829 if (fTopLineIndex >= fLines.size()) {
830 break;
831 }
832 fTopLineIndex++;
833 loadLineData();
834 updateTextArea();
835 break;
836 }
837 case SWT.PAGE_DOWN: {
838 fTopLineIndex += Math.max(fNumVisibleLines - 1, 1);
839 loadLineData();
840 updateTextArea();
841 break;
842 }
843 case SWT.ARROW_UP: {
844 //if (fLines.size() == 0 || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
845 if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
846 break;
847 }
848 fTopLineIndex--;
849 loadLineData();
850 updateTextArea();
851 break;
852 }
853 case SWT.PAGE_UP: {
854 fTopLineIndex -= Math.max(fNumVisibleLines - 1, 1);
855 loadLineData();
856 updateTextArea();
857 break;
858 }
859 case SWT.HOME: {
860 //selectAndReveal(0);
861 setTopPosition(0.0);
862 break;
863 }
864 case SWT.END: {
865 //if (fTrace.getNbEvents() > 0) {
866 //selectAndReveal(fTrace.getNbEvents() - 1);
867 //}
868 double ratio = 1.0;
869 double delta = Math.pow(10, -15);
870 fLines.clear();
871 while (fLines.size() == 0) {
872 setTopPosition(ratio);
873 if (ratio == 0.0) {
874 break;
875 }
876 delta = Math.min(delta * 10, 0.1);
877 ratio = Math.max(ratio - delta, 0.0);
878 }
879 break;
880 }
881 default:
882 break;
883 }
884 //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
885 if (e.detail != SWT.NONE) {
886 fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
887 }
888
889 fHoldSelection = 0;
890 }
891
892 @Override
893 public void widgetDefaultSelected(SelectionEvent e) {
894 }
895
896 // ------------------------------------------------------------------------
29ddb729
PT
897 // MouseListener (Slider)
898 // ------------------------------------------------------------------------
899
900 /**
0336f981 901 * @since 1.1
29ddb729
PT
902 */
903 @Override
904 public void mouseDown(MouseEvent e) {
905 }
906
907 /**
0336f981 908 * @since 1.1
29ddb729
PT
909 */
910 @Override
911 public void mouseUp(MouseEvent e) {
912 if (e.button != 1) {
913 return;
914 }
915 /*
916 * When the mouse button is released, perform the refresh immediately
917 * and interrupt and discard the slider throttler.
918 */
919 if (fSliderThrottler != null) {
920 fSliderThrottler.interrupt();
921 fSliderThrottler = null;
922 }
923 Event event = new Event();
924 event.widget = this;
925 event.detail = SWT.NONE;
926 widgetSelected(new SelectionEvent(event));
927 }
928
929 /**
0336f981 930 * @since 1.1
29ddb729
PT
931 */
932 @Override
933 public void mouseDoubleClick(MouseEvent e) {
934 }
935
936 // ------------------------------------------------------------------------
7d048a33
PT
937 // KeyListener (StyledText)
938 // ------------------------------------------------------------------------
939
940 @Override
941 public void keyPressed(KeyEvent e) {
942 if (fLines.size() == 0) {
943 return;
944 }
945 int caretOffset = fStyledText.getCaretOffset();
946 int previousCaretOffset = getPreviousCaretOffset(e.time);
947 int previousLineAtCaretPosition = fStyledText.getLineAtOffset(previousCaretOffset);
948 int previousColumnAtCaretPosition = getPreviousCaretOffset(e.time) - fStyledText.getOffsetAtLine(previousLineAtCaretPosition);
949 switch (e.keyCode) {
950 case SWT.ARROW_DOWN: {
951 if (previousLineAtCaretPosition < (fNumVisibleLines - 2)) {
952 break;
953 }
954 fHoldSelection++;
955 fTopLineIndex++;
956 loadLineData();
957 updateTextArea();
958 fHoldSelection--;
959 LineData lineData = fLines.get(fTopLineIndex + fStyledText.getLineAtOffset(fStyledText.getCaretOffset()));
960 if (!lineData.location.equals(fSelectedLocation)) {
961 fSelectedLocation = lineData.location;
962 refreshLineBackgrounds();
963 sendSelectionEvent(lineData);
964 }
965 break;
966 }
967 case SWT.PAGE_DOWN: {
968 if (previousLineAtCaretPosition >= (fNumVisibleLines - 1)) {
969 fHoldSelection++;
970 if (fLines.get(fTopLineIndex + previousLineAtCaretPosition).rank % 2 == 0) {
971 fStyledText.setLineBackground(previousLineAtCaretPosition, 1, COLOR_BACKGROUND_EVEN);
972 } else {
973 fStyledText.setLineBackground(previousLineAtCaretPosition, 1, COLOR_BACKGROUND_ODD);
974 }
975 fSelectedLocation = null;
976 fTopLineIndex += Math.max(fNumVisibleLines - 1, 1);
977 loadLineData();
978 updateTextArea();
979 fHoldSelection--;
980 }
981 int line = Math.min(fNumVisibleLines - 1, fStyledText.getLineCount() - 1);
982 int offset = fStyledText.getOffsetAtLine(line);
983 fStyledText.setSelection(offset + Math.min(previousColumnAtCaretPosition, fLines.get(fTopLineIndex + line).string.length()));
984 break;
985 }
986 case SWT.ARROW_RIGHT: {
987 if (previousCaretOffset < fStyledText.getCharCount() || previousLineAtCaretPosition < (fNumVisibleLines - 2)) {
988 break;
989 }
990 fHoldSelection++;
991 fTopLineIndex++;
992 loadLineData();
993 updateTextArea();
994 fHoldSelection--;
995 fStyledText.setSelection(fStyledText.getCaretOffset() + 1);
996 break;
997 }
998 case SWT.ARROW_UP: {
999 if (previousLineAtCaretPosition > 0) {
1000 break;
1001 }
1002 if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
1003 break;
1004 }
1005 fHoldSelection++;
1006 fTopLineIndex--;
1007 loadLineData();
1008 updateTextArea();
1009 fHoldSelection--;
1010 LineData lineData = fLines.get(fTopLineIndex);
1011 if (!lineData.location.equals(fSelectedLocation)) {
1012 fSelectedLocation = lineData.location;
1013 refreshLineBackgrounds();
1014 sendSelectionEvent(lineData);
1015 }
1016 fStyledText.setSelection(caretOffset);
1017 break;
1018 }
1019 case SWT.PAGE_UP: {
1020 if (previousLineAtCaretPosition > 0) {
1021 break;
1022 }
1023 fHoldSelection++;
1024 fTopLineIndex -= Math.max(fNumVisibleLines - 1, 1);
1025 loadLineData();
1026 updateTextArea();
1027 fHoldSelection--;
1028 LineData lineData = fLines.get(fTopLineIndex);
1029 if (!lineData.location.equals(fSelectedLocation)) {
1030 fSelectedLocation = lineData.location;
1031 refreshLineBackgrounds();
1032 sendSelectionEvent(lineData);
1033 }
1034 fStyledText.setSelection(caretOffset);
1035 break;
1036 }
1037 case SWT.ARROW_LEFT: {
1038 if (previousCaretOffset > 0) {
1039 break;
1040 }
1041 if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
1042 break;
1043 }
1044 long topRank = fLines.get(fTopLineIndex).rank;
1045 fHoldSelection++;
1046 fTopLineIndex--;
1047 loadLineData();
1048 updateTextArea();
1049 fHoldSelection--;
1050 LineData lineData = fLines.get(fTopLineIndex);
1051 if (!lineData.location.equals(fSelectedLocation)) {
1052 fSelectedLocation = lineData.location;
1053 refreshLineBackgrounds();
1054 sendSelectionEvent(lineData);
1055 }
1056 if (topRank != fLines.get(fTopLineIndex).rank) {
1057 fStyledText.setSelection(fLines.get(fTopLineIndex).string.length());
1058 }
1059 break;
1060 }
1061 case SWT.HOME: {
1062 if ((e.stateMask & SWT.CTRL) == 0) {
1063 break;
1064 }
1065 //selectAndReveal(0);
1066 setTopPosition(0.0);
1067 LineData lineData = fLines.get(fTopLineIndex);
1068 if (!lineData.location.equals(fSelectedLocation)) {
1069 fSelectedLocation = lineData.location;
1070 refreshLineBackgrounds();
1071 sendSelectionEvent(lineData);
1072 }
1073 break;
1074 }
1075 case SWT.END: {
1076 if ((e.stateMask & SWT.CTRL) == 0) {
1077 break;
1078 }
1079 //if (fTrace.getNbEvents() > 0) {
1080 //selectAndReveal(fTrace.getNbEvents() - 1);
1081 //}
1082 double ratio = 1.0;
1083 double delta = Math.pow(10, -15);
1084 fLines.clear();
1085 while (fLines.size() == 0) {
1086 setTopPosition(ratio);
1087 if (ratio == 0.0) {
1088 break;
1089 }
1090 delta = Math.min(delta * 10, 0.1);
1091 ratio = Math.max(ratio - delta, 0.0);
1092 }
1093 LineData lineData = fLines.get(fTopLineIndex);
1094 if (!lineData.location.equals(fSelectedLocation)) {
1095 fSelectedLocation = lineData.location;
1096 refreshLineBackgrounds();
1097 sendSelectionEvent(lineData);
1098 }
1099 break;
1100 }
1101 default:
1102 break;
1103 }
1104 //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
1105 updateHighlightedRank();
1106 fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
1107 }
1108
1109 @Override
1110 public void keyReleased(KeyEvent e) {
1111 }
1112
1113 // ------------------------------------------------------------------------
1114 // CaretListener (StyledText)
1115 // ------------------------------------------------------------------------
1116
1117 @Override
1118 public void caretMoved(CaretEvent event) {
1119 if (fHoldSelection == 0) {
1120 int line = fStyledText.getLineAtOffset(event.caretOffset);
1121 if (fTopLineIndex + line < fLines.size()) {
1122 LineData lineData = fLines.get(fTopLineIndex + line);
1123 if (!lineData.location.equals(fSelectedLocation)) {
1124 fSelectedLocation = lineData.location;
1125 refreshLineBackgrounds();
1126 sendSelectionEvent(lineData);
1127 }
1128 }
1129 }
1130 storeCaretPosition(event.time, event.caretOffset);
1131 if (fHoldSelection == 0) {
1132 Point caret = fStyledText.getLocationAtOffset(fStyledText.getCaretOffset());
1133 Point origin = fScrolledComposite.getOrigin();
1134 if (origin.x > caret.x) {
1135 origin.x = caret.x;
1136 } else if (caret.x - origin.x > fScrolledComposite.getSize().x) {
1137 origin.x = caret.x - fScrolledComposite.getSize().x + 1;
1138 }
1139 fScrolledComposite.setOrigin(origin);
1140 }
1141 }
1142
1143 // ------------------------------------------------------------------------
1144 // MouseMoveListener (StyledText)
1145 // ------------------------------------------------------------------------
1146
1147 @Override
1148 public void mouseMove(MouseEvent e) {
1149 fCursorYCoordinate = e.y;
1150 if (e.y < 0 || e.y > fStyledText.getSize().y) {
1151 if (fHighlightedRank != Long.MIN_VALUE) {
1152 fHighlightedRank = Long.MIN_VALUE;
1153 refreshLineBackgrounds();
1154 }
1155 return;
1156 }
1157 int offset = fStyledText.getOffsetAtLocation(new Point(0, e.y));
1158 int line = fStyledText.getLineAtOffset(offset);
1159 if (line < fLines.size() - fTopLineIndex) {
1160 LineData lineData = fLines.get(fTopLineIndex + line);
1161 if (fHighlightedRank != lineData.rank) {
1162 fHighlightedRank = lineData.rank;
1163 refreshLineBackgrounds();
1164 }
1165 } else {
1166 if (fHighlightedRank != Long.MIN_VALUE) {
1167 fHighlightedRank = Long.MIN_VALUE;
1168 refreshLineBackgrounds();
1169 }
1170 }
1171 }
1172
1173 // ------------------------------------------------------------------------
1174 // MouseTrackListener (StyledText)
1175 // ------------------------------------------------------------------------
1176
1177 @Override
1178 public void mouseExit(MouseEvent e) {
1179 fCursorYCoordinate = -1;
1180 if (fHighlightedRank != Long.MIN_VALUE) {
1181 fHighlightedRank = Long.MIN_VALUE;
1182 refreshLineBackgrounds();
1183 }
1184 }
1185
1186 @Override
1187 public void mouseEnter(MouseEvent e) {
1188 fCursorYCoordinate = e.y;
1189 }
1190
1191 @Override
1192 public void mouseHover(MouseEvent e) {
1193 }
1194
1195 // ------------------------------------------------------------------------
1196 // MouseWheelListener (StyledText)
1197 // ------------------------------------------------------------------------
1198
1199 @Override
1200 public void mouseScrolled(MouseEvent e) {
1201 if (fLines.size() == 0) {
1202 return;
1203 }
1204 fHoldSelection++;
1205 fTopLineIndex -= e.count;
1206 loadLineData();
1207 updateTextArea();
1208 fHoldSelection = 0;
1209 //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
1210 updateHighlightedRank();
1211 fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
1212 }
1213
1214}
This page took 0.203485 seconds and 5 git commands to generate.