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