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