-/*******************************************************************************\r
- * Copyright (c) 2010, 2012 Ericsson\r
- * \r
- * All rights reserved. This program and the accompanying materials are\r
- * made available under the terms of the Eclipse Public License v1.0 which\r
- * accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- * \r
- * Contributors:\r
- * Patrick Tasse - Initial API and implementation\r
- ******************************************************************************/\r
-\r
-package org.eclipse.linuxtools.tmf.ui.widgets.rawviewer;\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;\r
-import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;\r
-import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;\r
-import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.CaretEvent;\r
-import org.eclipse.swt.custom.CaretListener;\r
-import org.eclipse.swt.custom.ScrolledComposite;\r
-import org.eclipse.swt.custom.StyledText;\r
-import org.eclipse.swt.events.ControlEvent;\r
-import org.eclipse.swt.events.ControlListener;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.KeyListener;\r
-import org.eclipse.swt.events.MouseAdapter;\r
-import org.eclipse.swt.events.MouseEvent;\r
-import org.eclipse.swt.events.MouseMoveListener;\r
-import org.eclipse.swt.events.MouseTrackListener;\r
-import org.eclipse.swt.events.MouseWheelListener;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.events.SelectionListener;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.Font;\r
-import org.eclipse.swt.graphics.FontData;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.Menu;\r
-import org.eclipse.swt.widgets.Slider;\r
-\r
-/**\r
- * TmfRawEventViewer allows for the display of the raw data for an arbitrarily\r
- * large number of TMF events.\r
- * \r
- * It is essentially a Composite of a StyledText area and a Slider, where the number\r
- * of visible lines in the StyledText control is set to fill the viewer display area.\r
- * An underlying data model is used to store a cache of event raw text line data.\r
- * The slider is ratio-based.\r
- *\r
- * @version 1.0\r
- * @author Patrick Tasse\r
- */\r
-public class TmfRawEventViewer extends Composite implements ControlListener, SelectionListener,\r
- KeyListener, CaretListener, MouseMoveListener, MouseTrackListener, MouseWheelListener {\r
-\r
- private static final Color COLOR_BACKGROUND_ODD = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);\r
- private static final Color COLOR_BACKGROUND_EVEN = new Color(Display.getDefault(), 242, 242, 242);\r
- private static final Color COLOR_BACKGROUND_SELECTED = new Color(Display.getDefault(), 231, 246, 254);\r
- private static final Color COLOR_BACKGROUND_HIGHLIGHTED = new Color(Display.getDefault(), 246, 252, 255);\r
- private static final int MAX_LINE_DATA_SIZE = 1000;\r
- private static final int SLIDER_MAX = 1000000;\r
-\r
- private ITmfTrace<?> fTrace;\r
- private ITmfContext fBottomContext;\r
- \r
- private ScrolledComposite fScrolledComposite;\r
- private Composite fTextArea;\r
- private StyledText fStyledText;\r
- private Font fFixedFont;\r
- private Slider fSlider;\r
-\r
- private List<LineData> fLines = new ArrayList<LineData>();\r
- private boolean fActualRanks = false;\r
- private int fTopLineIndex;\r
- private int fLastTopLineIndex;\r
- private CaretPosition[] fStoredCaretPosition = new CaretPosition[]\r
- { new CaretPosition(0, 0), new CaretPosition(0,0)};\r
- private int fNumVisibleLines;\r
- private ITmfLocation<?> fSelectedLocation = null;\r
- private long fHighlightedRank = Long.MIN_VALUE;\r
- private int fCursorYCoordinate = -1;\r
- private int fHoldSelection = 0;\r
-\r
- private static class LineData {\r
- long rank;\r
- ITmfLocation<?> location;\r
- String string;\r
- public LineData(long rank, ITmfLocation<?> location, String string) {\r
- this.rank = rank;\r
- this.location = location;\r
- if (string.length() == 0) {\r
- this.string = " "; // workaround for setLineBackground has no effect on empty line //$NON-NLS-1$\r
- } else {\r
- this.string = string;\r
- }\r
- }\r
- @Override\r
- public String toString() {\r
- return rank + " [" + location + "]: " + string; //$NON-NLS-1$ //$NON-NLS-2$\r
- }\r
- }\r
-\r
- private static class CaretPosition {\r
- int time;\r
- int caretOffset;\r
- public CaretPosition(int time, int caretOffset) {\r
- this.time = time;\r
- this.caretOffset = caretOffset;\r
- }\r
- }\r
- \r
- // ------------------------------------------------------------------------\r
- // Constructor\r
- // ------------------------------------------------------------------------\r
-\r
- /**\r
- * Constructor\r
- * @param parent The parent composite\r
- * @param style The style bits\r
- */\r
- public TmfRawEventViewer(Composite parent, int style) {\r
- super(parent, style & (~SWT.H_SCROLL) & (~SWT.V_SCROLL));\r
-\r
- // Set the layout\r
- GridLayout gridLayout = new GridLayout();\r
- gridLayout.numColumns = 2;\r
- gridLayout.horizontalSpacing = 0;\r
- gridLayout.verticalSpacing = 0;\r
- gridLayout.marginWidth = 0;\r
- gridLayout.marginHeight = 0;\r
- setLayout(gridLayout);\r
- \r
- // Create the controls\r
- createTextArea(style & SWT.H_SCROLL);\r
- createSlider(style & SWT.V_SCROLL);\r
- \r
- // Prevent the slider from being traversed\r
- setTabList(new Control[] { fScrolledComposite });\r
- }\r
- \r
- @Override\r
- public void dispose() {\r
- if (fFixedFont != null) {\r
- fFixedFont.dispose();\r
- fFixedFont = null;\r
- }\r
- super.dispose();\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Text area handling\r
- // ------------------------------------------------------------------------\r
-\r
- /**\r
- * Create the text area and add listeners\r
- */\r
- private void createTextArea(int style) {\r
- fScrolledComposite = new ScrolledComposite(this, style);\r
- fScrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
- fTextArea = new Composite(fScrolledComposite, SWT.NONE);\r
- fTextArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
- fScrolledComposite.setContent(fTextArea);\r
- fScrolledComposite.setExpandHorizontal(true);\r
- fScrolledComposite.setExpandVertical(true);\r
- fScrolledComposite.setAlwaysShowScrollBars(true);\r
- fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));\r
- fScrolledComposite.addControlListener(this);\r
-\r
- GridLayout textAreaGridLayout = new GridLayout();\r
- textAreaGridLayout.marginHeight = 0;\r
- textAreaGridLayout.marginWidth = 0;\r
- fTextArea.setLayout(textAreaGridLayout);\r
-\r
- if (fFixedFont == null) {\r
- if (System.getProperty("os.name").contains("Windows")) { //$NON-NLS-1$ //$NON-NLS-2$\r
- fFixedFont = new Font(Display.getCurrent(), new FontData("Courier New", 10, SWT.NORMAL)); //$NON-NLS-1$\r
- } else {\r
- fFixedFont = new Font(Display.getCurrent(), new FontData("Monospace", 10, SWT.NORMAL)); //$NON-NLS-1$\r
- }\r
- }\r
- \r
- fStyledText = new StyledText(fTextArea, SWT.READ_ONLY);\r
- fStyledText.setFont(fFixedFont);\r
- fStyledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));\r
- \r
- fStyledText.addCaretListener(this);\r
- fStyledText.addMouseMoveListener(this);\r
- fStyledText.addMouseTrackListener(this);\r
- fStyledText.addMouseWheelListener(this);\r
- fStyledText.addListener(SWT.MouseWheel, new Listener() { // disable mouse scroll of horizontal scroll bar\r
- @Override\r
- public void handleEvent(Event event) { event.doit = false; }});\r
- fStyledText.addKeyListener(this);\r
- \r
- fTextArea.setBackground(fStyledText.getBackground());\r
- fTextArea.addMouseListener(new MouseAdapter() {\r
- @Override\r
- public void mouseDown(MouseEvent e) {\r
- fTextArea.setFocus();\r
- }});\r
- } \r
-\r
- // ------------------------------------------------------------------------\r
- // Slider handling\r
- // ------------------------------------------------------------------------\r
-\r
- private void createSlider(int style) {\r
- fSlider = new Slider(this, SWT.VERTICAL);\r
- fSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));\r
- fSlider.setValues(0, 0, SLIDER_MAX, SLIDER_MAX, 1, 1);\r
- fSlider.addSelectionListener(this);\r
- if ((style & SWT.V_SCROLL) == 0) {\r
- fSlider.setVisible(false);\r
- }\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Controls interactions\r
- // ------------------------------------------------------------------------\r
-\r
- @Override\r
- public boolean setFocus() {\r
- boolean isVisible = isVisible();\r
- if (isVisible) {\r
- fTextArea.setFocus();\r
- }\r
- return isVisible;\r
- }\r
- \r
- @Override\r
- public void setMenu(Menu menu) {\r
- fStyledText.setMenu(menu);\r
- }\r
-\r
- /**\r
- * Sets the trace and updates the content\r
- * @param trace The trace to set\r
- */\r
- public void setTrace(ITmfTrace<?> trace) {\r
- fTrace = trace;\r
- fTopLineIndex = 0;\r
- fLines.clear();\r
- refreshEventCount();\r
- }\r
-\r
- /**\r
- * Refreshes the event count, updates the slider thumb and loads display\r
- */\r
- public void refreshEventCount() {\r
- if (fTrace != null) {\r
- if (fTrace.getNbEvents() > 0) {\r
- fSlider.setThumb((int) Math.max(SLIDER_MAX / fTrace.getNbEvents(), 1));\r
- } else {\r
- fSlider.setThumb(SLIDER_MAX);\r
- }\r
-\r
- if (!isVisible()) return;\r
- \r
- if (fLines.size() == 0) {\r
- setTopRank(0);\r
- } else if (fLines.size() < fNumVisibleLines) {\r
- fBottomContext = null;\r
- loadLineData();\r
- fillTextArea();\r
- //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));\r
- fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));\r
- }\r
- }\r
- }\r
- \r
- /**\r
- * Selects the event of given rank and makes it visible.\r
- * @param rank The rank of event\r
- */\r
- public void selectAndReveal(long rank) {\r
- if (fTrace == null || !isVisible()) {\r
- return;\r
- }\r
- if (fActualRanks && fTopLineIndex < fLines.size() && rank >= fLines.get(fTopLineIndex).rank) {\r
- int lastVisibleIndex = Math.min(fTopLineIndex + fNumVisibleLines, fLines.size()) - 1;\r
- if (rank <= fLines.get(lastVisibleIndex).rank) {\r
- for (int i = fTopLineIndex; i < fLines.size(); i++) {\r
- if (fLines.get(i).rank == rank) {\r
- fSelectedLocation = fLines.get(i).location;\r
- break;\r
- }\r
- }\r
- refreshLineBackgrounds();\r
- return;\r
- }\r
- }\r
- setTopRank(rank);\r
- if (fLines.size() > 0 && fHoldSelection == 0) {\r
- fSelectedLocation = fLines.get(0).location;\r
- refreshLineBackgrounds();\r
- }\r
- }\r
- /**\r
- * Add a selection listener\r
- * @param listener A listener to add\r
- */\r
- public void addSelectionListener(Listener listener) {\r
- checkWidget();\r
- if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);\r
- addListener (SWT.Selection, listener);\r
- }\r
-\r
- /**\r
- * Remove selection listener\r
- * @param listener A listener to remove\r
- */\r
- public void removeSelectionListener(Listener listener) {\r
- checkWidget();\r
- if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);\r
- removeListener(SWT.Selection, listener);\r
- }\r
-\r
- private void sendSelectionEvent(LineData lineData) {\r
- Event event = new Event();\r
- if (fActualRanks) {\r
- event.data = Long.valueOf(lineData.rank);\r
- } else {\r
- event.data = lineData.location;\r
- }\r
- notifyListeners(SWT.Selection, event);\r
- }\r
- \r
- private void setTopRank(long rank) {\r
- fBottomContext = fTrace.seekEvent(rank);\r
- if (fBottomContext == null) {\r
- return;\r
- }\r
- fLines.clear();\r
- fActualRanks = true;\r
- fTopLineIndex = 0;\r
- loadLineData();\r
- refreshTextArea();\r
- if (fLines.size() == 0) {\r
- fSlider.setSelection(0);\r
- } else {\r
- //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));\r
- fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));\r
- }\r
- }\r
- \r
- private void setTopPosition(double ratio) {\r
- fBottomContext = fTrace.seekEvent(ratio);\r
- if (fBottomContext == null) {\r
- return;\r
- }\r
- fBottomContext.setRank(0);\r
- fLines.clear();\r
- fActualRanks = false;\r
- fTopLineIndex = 0;\r
- loadLineData();\r
- refreshTextArea();\r
- }\r
- \r
- private void loadLineData() {\r
- if (fTopLineIndex < 0) {\r
- //if (fLines.size() > 0 && fLines.get(0).rank > 0) {\r
- //long endRank = fLines.get(0).rank;\r
- //long startRank = Math.max(0, endRank - fNumVisibleLines);\r
- //TmfContext context = fTrace.seekEvent(startRank);\r
- //int index = 0;\r
- //while (context.getRank() < endRank) {\r
- //long rank = context.getRank();\r
- //ITmfLocation<?> location = context.getLocation();\r
- //TmfEvent event = fTrace.getNextEvent(context);\r
- //String[] lines = event.getRawText().split("\r?\n");\r
- //for (int i = 0; i < lines.length; i++) {\r
- //String line = lines[i];\r
- //LineData lineData = new LineData(rank, location, line); \r
- //fLines.add(index++, lineData);\r
- //fTopLineIndex++;\r
- //fLastTopLineIndex++;\r
- //}\r
- //}\r
- //}\r
- if (fLines.size() > 0 && fTrace.getLocationRatio(fLines.get(0).location) > 0) {\r
- double lastRatio = fTrace.getLocationRatio(fLines.get(fLines.size() - 1).location);\r
- double firstRatio = fTrace.getLocationRatio(fLines.get(0).location);\r
- double delta;\r
- boolean singleEvent = false;\r
- if (firstRatio != lastRatio) {\r
- // approximate ratio of at least 20 items\r
- delta = Math.max(20, fNumVisibleLines) * (lastRatio - firstRatio) / (fLines.size() - 1);\r
- } else {\r
- delta = Math.pow(10, -15);\r
- singleEvent = true;\r
- }\r
- while (fTopLineIndex < 0) {\r
- ITmfLocation<?> endLocation = fLines.get(0).location;\r
- firstRatio = Math.max(0, firstRatio - delta);\r
- ITmfContext context = fTrace.seekEvent(firstRatio);\r
- ITmfLocation<?> location;\r
- int index = 0;\r
- long rank = 0;\r
- while (!context.getLocation().equals(endLocation)) {\r
- location = context.getLocation().clone();\r
- ITmfEvent event = fTrace.getNext(context);\r
- if (event == null) {\r
- break;\r
- }\r
- if (event.getContent() != null && event.getContent().getValue() != null) {\r
- String[] lines = event.getContent().getValue().toString().split("\r?\n"); //$NON-NLS-1$\r
- for (int i = 0; i < lines.length; i++) {\r
- String line = lines[i];\r
- LineData lineData = new LineData(rank, location, line); \r
- fLines.add(index++, lineData);\r
- fTopLineIndex++;\r
- fLastTopLineIndex++;\r
- }\r
- } else {\r
- LineData lineData = new LineData(rank, location, ""); //$NON-NLS-1$\r
- fLines.add(index++, lineData);\r
- fTopLineIndex++;\r
- fLastTopLineIndex++;\r
- }\r
- rank++;\r
- }\r
- long rankOffset = fLines.get(index).rank - rank;\r
- for (int i = 0; i < index; i++) {\r
- fLines.get(i).rank += rankOffset;\r
- }\r
- if (firstRatio == 0) {\r
- break;\r
- }\r
- if (singleEvent) {\r
- delta = Math.min(delta * 10, 0.1);\r
- }\r
- }\r
- }\r
- if (fTopLineIndex < 0) {\r
- fTopLineIndex = 0;\r
- }\r
- }\r
- \r
- while (fLines.size() - fTopLineIndex < fNumVisibleLines) {\r
- if (fBottomContext == null) {\r
- if (fLines.size() == 0) {\r
- fBottomContext = fTrace.seekEvent(0);\r
- } else {\r
- //fBottomContext = fTrace.seekEvent(fLines.get(fLines.size() - 1).rank + 1);\r
- fBottomContext = fTrace.seekEvent(fLines.get(fLines.size() - 1).location);\r
- fTrace.getNext(fBottomContext);\r
- }\r
- if (fBottomContext == null) {\r
- break;\r
- }\r
- }\r
- long rank = fBottomContext.getRank();\r
- ITmfLocation<?> location = fBottomContext.getLocation() != null ? fBottomContext.getLocation().clone() : null;\r
- ITmfEvent event = fTrace.getNext(fBottomContext);\r
- if (event == null) {\r
- break;\r
- }\r
- if (event.getContent() != null && event.getContent().getValue() != null) {\r
- for (String line : event.getContent().getValue().toString().split("\r?\n")) { //$NON-NLS-1$\r
- int crPos;\r
- if ((crPos = line.indexOf('\r')) != -1) {\r
- line = line.substring(0, crPos);\r
- }\r
- LineData lineData = new LineData(rank, location, line); \r
- fLines.add(lineData);\r
- }\r
- } else {\r
- LineData lineData = new LineData(rank, location, ""); //$NON-NLS-1$\r
- fLines.add(lineData);\r
- }\r
- }\r
- fTopLineIndex = Math.max(0, Math.min(fTopLineIndex, fLines.size() - 1));\r
- \r
- if (fLines.size() > MAX_LINE_DATA_SIZE) {\r
- if (fTopLineIndex < MAX_LINE_DATA_SIZE / 2) {\r
- long rank = fLines.get(MAX_LINE_DATA_SIZE - 1).rank;\r
- for (int i = MAX_LINE_DATA_SIZE; i < fLines.size(); i++) {\r
- if (fLines.get(i).rank > rank) {\r
- fLines.subList(i, fLines.size()).clear();\r
- fBottomContext = null;\r
- break;\r
- }\r
- }\r
- } else {\r
- long rank = fLines.get(fLines.size() - MAX_LINE_DATA_SIZE).rank;\r
- for (int i = fLines.size() - MAX_LINE_DATA_SIZE - 1; i >= 0; i--) {\r
- if (fLines.get(i).rank < rank) {\r
- fLines.subList(0, i + 1).clear();\r
- fTopLineIndex -= (i + 1);\r
- fLastTopLineIndex -= (i + 1);\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- \r
- private void refreshTextArea() {\r
- fStyledText.setText(""); //$NON-NLS-1$\r
- for (int i = 0; i < fLines.size() - fTopLineIndex && i < fNumVisibleLines; i++) {\r
- if (i > 0) fStyledText.append("\n"); //$NON-NLS-1$\r
- LineData lineData = fLines.get(fTopLineIndex + i);\r
- fStyledText.append(lineData.string);\r
- setLineBackground(i, lineData);\r
- }\r
- fTextArea.layout();\r
- fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));\r
- fLastTopLineIndex = fTopLineIndex;\r
- }\r
-\r
- private void fillTextArea() {\r
- int nextLine = fStyledText.getCharCount() == 0 ? 0 : fStyledText.getLineCount();\r
- for (int i = nextLine; i < fLines.size() - fTopLineIndex && i < fNumVisibleLines; i++) {\r
- if (i > 0) fStyledText.append("\n"); //$NON-NLS-1$\r
- LineData lineData = fLines.get(fTopLineIndex + i);\r
- fStyledText.append(lineData.string);\r
- setLineBackground(i, lineData);\r
- }\r
- int endLine = Math.min(fNumVisibleLines, fLines.size());\r
- if (endLine < fStyledText.getLineCount()) {\r
- int endOffset = fStyledText.getOffsetAtLine(endLine) - 1;\r
- if (endOffset > fStyledText.getCharCount()) {\r
- fHoldSelection++;\r
- fStyledText.replaceTextRange(endOffset, fStyledText.getCharCount() - endOffset, ""); //$NON-NLS-1$\r
- fHoldSelection--;\r
- }\r
- }\r
- fTextArea.layout();\r
- fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));\r
- }\r
-\r
- private void updateTextArea() {\r
- if (fTopLineIndex < fLastTopLineIndex) {\r
- StringBuffer insertedText = new StringBuffer();\r
- for (int i = fTopLineIndex; i < fLastTopLineIndex; i++) {\r
- insertedText.append(fLines.get(i).string + "\n"); //$NON-NLS-1$\r
- }\r
- fStyledText.replaceTextRange(0, 0, insertedText.toString());\r
- for (int i = 0; i < fLastTopLineIndex - fTopLineIndex; i++) {\r
- LineData lineData = fLines.get(fTopLineIndex + i);\r
- setLineBackground(i, lineData);\r
- }\r
- fLastTopLineIndex = fTopLineIndex;\r
- } else if (fTopLineIndex > fLastTopLineIndex) {\r
- int length = 0;\r
- for (int i = 0; i < fTopLineIndex - fLastTopLineIndex && i < fNumVisibleLines; i++) {\r
- length += fLines.get(i + fLastTopLineIndex).string.length();\r
- if (i < fStyledText.getLineCount()) length += 1;\r
- }\r
- fStyledText.replaceTextRange(0, length, ""); //$NON-NLS-1$\r
- fLastTopLineIndex = fTopLineIndex;\r
- fillTextArea();\r
- }\r
- int endLine = Math.min(fNumVisibleLines, fLines.size());\r
- if (endLine < fStyledText.getLineCount()) {\r
- int endOffset = fStyledText.getOffsetAtLine(endLine) - 1;\r
- if (endOffset > fStyledText.getCharCount()) {\r
- fStyledText.replaceTextRange(endOffset, fStyledText.getCharCount() - endOffset, ""); //$NON-NLS-1$\r
- }\r
- }\r
- fTextArea.layout();\r
- fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));\r
- }\r
- \r
- private void refreshLineBackgrounds() {\r
- for (int i = 0; (i < fStyledText.getLineCount()) && (i < fNumVisibleLines) && (i < fLines.size() - fTopLineIndex); i++) {\r
- LineData lineData = fLines.get(fTopLineIndex + i);\r
- setLineBackground(i, lineData);\r
- }\r
- }\r
-\r
- private void setLineBackground(int index, LineData lineData) {\r
- if (lineData.location.equals(fSelectedLocation)) {\r
- fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_SELECTED);\r
- } else if (lineData.rank == fHighlightedRank) {\r
- fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_HIGHLIGHTED);\r
- } else if (lineData.rank % 2 == 0) {\r
- fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_EVEN);\r
- } else {\r
- fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_ODD);\r
- }\r
- }\r
-\r
- private void storeCaretPosition(int time, int caretOffset) {\r
- if (fStoredCaretPosition[0].time == time) {\r
- fStoredCaretPosition[0].caretOffset = caretOffset;\r
- } else {\r
- fStoredCaretPosition[1] = fStoredCaretPosition[0];\r
- fStoredCaretPosition[0] = new CaretPosition(time, caretOffset);\r
- }\r
- }\r
- \r
- private int getPreviousCaretOffset(int time) {\r
- if (fStoredCaretPosition[0].time == time) {\r
- return fStoredCaretPosition[1].caretOffset;\r
- }\r
- return fStoredCaretPosition[0].caretOffset;\r
- }\r
-\r
- private void updateHighlightedRank() {\r
- if (fCursorYCoordinate < 0 || fCursorYCoordinate > fStyledText.getSize().y) {\r
- if (fHighlightedRank != Long.MIN_VALUE) {\r
- fHighlightedRank = Long.MIN_VALUE;\r
- refreshLineBackgrounds();\r
- }\r
- return;\r
- }\r
- int offset = fStyledText.getOffsetAtLocation(new Point(0, fCursorYCoordinate));\r
- int line = fStyledText.getLineAtOffset(offset);\r
- if (line < fLines.size() - fTopLineIndex) {\r
- LineData lineData = fLines.get(fTopLineIndex + line);\r
- if (fHighlightedRank != lineData.rank) {\r
- fHighlightedRank = lineData.rank;\r
- refreshLineBackgrounds();\r
- }\r
- } else {\r
- if (fHighlightedRank != Long.MIN_VALUE) {\r
- fHighlightedRank = Long.MIN_VALUE;\r
- refreshLineBackgrounds();\r
- }\r
- }\r
- }\r
- \r
- // ------------------------------------------------------------------------\r
- // ControlListener (ScrolledComposite)\r
- // ------------------------------------------------------------------------\r
- \r
- @Override\r
- public void controlResized(ControlEvent event) {\r
- int areaHeight = fScrolledComposite.getSize().y;\r
- if (fScrolledComposite.getHorizontalBar() != null) {\r
- areaHeight -= fScrolledComposite.getHorizontalBar().getSize().y;\r
- }\r
- int lineHeight = fStyledText.getLineHeight();\r
- fNumVisibleLines = Math.max((areaHeight + lineHeight - 1) / lineHeight, 1);\r
-\r
- if (fBottomContext != null) {\r
- loadLineData();\r
- fillTextArea();\r
- }\r
- }\r
-\r
- @Override\r
- public void controlMoved(ControlEvent e) {\r
- }\r
- \r
- // ------------------------------------------------------------------------\r
- // SelectionListener (Slider)\r
- // ------------------------------------------------------------------------\r
- \r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- fTextArea.setFocus();\r
- if (fLines.size() == 0) {\r
- return;\r
- }\r
- if (e.detail == SWT.DRAG) {\r
- return;\r
- }\r
- fHoldSelection++;\r
- switch (e.detail) {\r
- case SWT.NONE: {\r
- //long rank = (long) (fTrace.getNbEvents() * ((double) fSlider.getSelection() / SLIDER_MAX));\r
- //setTopRank(rank);\r
- if (fSlider.getSelection() == 0 || fSlider.getThumb() == SLIDER_MAX) {\r
- fLines.clear();\r
- setTopPosition(0.0);\r
- break;\r
- }\r
- double ratio = (double) fSlider.getSelection() / (SLIDER_MAX - fSlider.getThumb());\r
- double delta = Math.pow(10, -15);\r
- fLines.clear();\r
- while (fLines.size() == 0) {\r
- setTopPosition(ratio);\r
- if (ratio == 0.0) break;\r
- delta = Math.min(delta * 10, 0.1);\r
- ratio = Math.max(ratio - delta, 0.0);\r
- }\r
- break;\r
- }\r
- case SWT.ARROW_DOWN: {\r
- if (fTopLineIndex >= fLines.size()) {\r
- break;\r
- }\r
- fTopLineIndex++;\r
- loadLineData();\r
- updateTextArea();\r
- break;\r
- }\r
- case SWT.PAGE_DOWN: {\r
- fTopLineIndex += Math.max(fNumVisibleLines - 1, 1);\r
- loadLineData();\r
- updateTextArea();\r
- break;\r
- }\r
- case SWT.ARROW_UP: {\r
- //if (fLines.size() == 0 || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {\r
- if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {\r
- break;\r
- }\r
- fTopLineIndex--;\r
- loadLineData();\r
- updateTextArea();\r
- break;\r
- }\r
- case SWT.PAGE_UP: {\r
- fTopLineIndex -= Math.max(fNumVisibleLines - 1, 1);\r
- loadLineData();\r
- updateTextArea();\r
- break;\r
- }\r
- case SWT.HOME: {\r
- //selectAndReveal(0);\r
- setTopPosition(0.0);\r
- break;\r
- }\r
- case SWT.END: {\r
- //if (fTrace.getNbEvents() > 0) {\r
- //selectAndReveal(fTrace.getNbEvents() - 1);\r
- //}\r
- double ratio = 1.0;\r
- double delta = Math.pow(10, -15);\r
- fLines.clear();\r
- while (fLines.size() == 0) {\r
- setTopPosition(ratio);\r
- if (ratio == 0.0) break;\r
- delta = Math.min(delta * 10, 0.1);\r
- ratio = Math.max(ratio - delta, 0.0);\r
- }\r
- break;\r
- }\r
- default:\r
- break;\r
- }\r
- //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));\r
- if (e.detail != SWT.NONE) {\r
- fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));\r
- }\r
- \r
- fHoldSelection = 0;\r
- }\r
-\r
- @Override\r
- public void widgetDefaultSelected(SelectionEvent e) {\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // KeyListener (StyledText)\r
- // ------------------------------------------------------------------------\r
- \r
- @Override\r
- public void keyPressed(KeyEvent e) {\r
- if (fLines.size() == 0) {\r
- return;\r
- }\r
- int caretOffset = fStyledText.getCaretOffset();\r
- int previousCaretOffset = getPreviousCaretOffset(e.time);\r
- int previousLineAtCaretPosition = fStyledText.getLineAtOffset(previousCaretOffset);\r
- int previousColumnAtCaretPosition = getPreviousCaretOffset(e.time) - fStyledText.getOffsetAtLine(previousLineAtCaretPosition);\r
- switch (e.keyCode) {\r
- case SWT.ARROW_DOWN: {\r
- if (previousLineAtCaretPosition < (fNumVisibleLines - 2)) {\r
- break;\r
- }\r
- fHoldSelection++;\r
- fTopLineIndex++;\r
- loadLineData();\r
- updateTextArea();\r
- fHoldSelection--;\r
- LineData lineData = fLines.get(fTopLineIndex + fStyledText.getLineAtOffset(fStyledText.getCaretOffset()));\r
- if (!lineData.location.equals(fSelectedLocation)) {\r
- fSelectedLocation = lineData.location;\r
- refreshLineBackgrounds();\r
- sendSelectionEvent(lineData);\r
- }\r
- break;\r
- }\r
- case SWT.PAGE_DOWN: {\r
- if (previousLineAtCaretPosition >= (fNumVisibleLines - 1)) {\r
- fHoldSelection++;\r
- if (fLines.get(fTopLineIndex + previousLineAtCaretPosition).rank % 2 == 0) {\r
- fStyledText.setLineBackground(previousLineAtCaretPosition, 1, COLOR_BACKGROUND_EVEN);\r
- } else {\r
- fStyledText.setLineBackground(previousLineAtCaretPosition, 1, COLOR_BACKGROUND_ODD);\r
- }\r
- fSelectedLocation = null;\r
- fTopLineIndex += Math.max(fNumVisibleLines - 1, 1);\r
- loadLineData();\r
- updateTextArea();\r
- fHoldSelection--;\r
- }\r
- int line = Math.min(fNumVisibleLines - 1, fStyledText.getLineCount() - 1);\r
- int offset = fStyledText.getOffsetAtLine(line);\r
- fStyledText.setSelection(offset + Math.min(previousColumnAtCaretPosition, fLines.get(fTopLineIndex + line).string.length()));\r
- break;\r
- }\r
- case SWT.ARROW_RIGHT: {\r
- if (previousCaretOffset < fStyledText.getCharCount() || previousLineAtCaretPosition < (fNumVisibleLines - 2)) {\r
- break;\r
- }\r
- fHoldSelection++;\r
- fTopLineIndex++;\r
- loadLineData();\r
- updateTextArea();\r
- fHoldSelection--;\r
- fStyledText.setSelection(fStyledText.getCaretOffset() + 1);\r
- break;\r
- }\r
- case SWT.ARROW_UP: {\r
- if (previousLineAtCaretPosition > 0) {\r
- break;\r
- }\r
- if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {\r
- break;\r
- }\r
- fHoldSelection++;\r
- fTopLineIndex--;\r
- loadLineData();\r
- updateTextArea();\r
- fHoldSelection--;\r
- LineData lineData = fLines.get(fTopLineIndex);\r
- if (!lineData.location.equals(fSelectedLocation)) {\r
- fSelectedLocation = lineData.location;\r
- refreshLineBackgrounds();\r
- sendSelectionEvent(lineData);\r
- }\r
- fStyledText.setSelection(caretOffset);\r
- break;\r
- }\r
- case SWT.PAGE_UP: {\r
- if (previousLineAtCaretPosition > 0) {\r
- break;\r
- }\r
- fHoldSelection++;\r
- fTopLineIndex -= Math.max(fNumVisibleLines - 1, 1);\r
- loadLineData();\r
- updateTextArea();\r
- fHoldSelection--;\r
- LineData lineData = fLines.get(fTopLineIndex);\r
- if (!lineData.location.equals(fSelectedLocation)) {\r
- fSelectedLocation = lineData.location;\r
- refreshLineBackgrounds();\r
- sendSelectionEvent(lineData);\r
- }\r
- fStyledText.setSelection(caretOffset);\r
- break;\r
- }\r
- case SWT.ARROW_LEFT: {\r
- if (previousCaretOffset > 0) {\r
- break;\r
- }\r
- if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {\r
- break;\r
- }\r
- long topRank = fLines.get(fTopLineIndex).rank;\r
- fHoldSelection++;\r
- fTopLineIndex--;\r
- loadLineData();\r
- updateTextArea();\r
- fHoldSelection--;\r
- LineData lineData = fLines.get(fTopLineIndex);\r
- if (!lineData.location.equals(fSelectedLocation)) {\r
- fSelectedLocation = lineData.location;\r
- refreshLineBackgrounds();\r
- sendSelectionEvent(lineData);\r
- }\r
- if (topRank != fLines.get(fTopLineIndex).rank) {\r
- fStyledText.setSelection(fLines.get(fTopLineIndex).string.length());\r
- }\r
- break;\r
- }\r
- case SWT.HOME: {\r
- if ((e.stateMask & SWT.CTRL) == 0) {\r
- break;\r
- }\r
- //selectAndReveal(0);\r
- setTopPosition(0.0);\r
- LineData lineData = fLines.get(fTopLineIndex);\r
- if (!lineData.location.equals(fSelectedLocation)) {\r
- fSelectedLocation = lineData.location;\r
- refreshLineBackgrounds();\r
- sendSelectionEvent(lineData);\r
- }\r
- break;\r
- }\r
- case SWT.END: {\r
- if ((e.stateMask & SWT.CTRL) == 0) {\r
- break;\r
- }\r
- //if (fTrace.getNbEvents() > 0) {\r
- //selectAndReveal(fTrace.getNbEvents() - 1);\r
- //}\r
- double ratio = 1.0;\r
- double delta = Math.pow(10, -15);\r
- fLines.clear();\r
- while (fLines.size() == 0) {\r
- setTopPosition(ratio);\r
- if (ratio == 0.0) break;\r
- delta = Math.min(delta * 10, 0.1);\r
- ratio = Math.max(ratio - delta, 0.0);\r
- }\r
- LineData lineData = fLines.get(fTopLineIndex);\r
- if (!lineData.location.equals(fSelectedLocation)) {\r
- fSelectedLocation = lineData.location;\r
- refreshLineBackgrounds();\r
- sendSelectionEvent(lineData);\r
- }\r
- break;\r
- }\r
- default:\r
- break;\r
- }\r
- //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));\r
- updateHighlightedRank();\r
- fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));\r
- }\r
-\r
- @Override\r
- public void keyReleased(KeyEvent e) {\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // CaretListener (StyledText)\r
- // ------------------------------------------------------------------------\r
- \r
- @Override\r
- public void caretMoved(CaretEvent event) {\r
- if (fHoldSelection == 0) {\r
- int line = fStyledText.getLineAtOffset(event.caretOffset);\r
- if (fTopLineIndex + line < fLines.size()) {\r
- LineData lineData = fLines.get(fTopLineIndex + line);\r
- if (!lineData.location.equals(fSelectedLocation)) {\r
- fSelectedLocation = lineData.location;\r
- refreshLineBackgrounds();\r
- sendSelectionEvent(lineData);\r
- }\r
- }\r
- }\r
- storeCaretPosition(event.time, event.caretOffset);\r
- if (fHoldSelection == 0) {\r
- Point caret = fStyledText.getLocationAtOffset(fStyledText.getCaretOffset());\r
- Point origin = fScrolledComposite.getOrigin();\r
- if (origin.x > caret.x) {\r
- origin.x = caret.x;\r
- } else if (caret.x - origin.x > fScrolledComposite.getSize().x) {\r
- origin.x = caret.x - fScrolledComposite.getSize().x + 1;\r
- }\r
- fScrolledComposite.setOrigin(origin);\r
- }\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // MouseMoveListener (StyledText)\r
- // ------------------------------------------------------------------------\r
- \r
- @Override\r
- public void mouseMove(MouseEvent e) {\r
- fCursorYCoordinate = e.y;\r
- if (e.y < 0 || e.y > fStyledText.getSize().y) {\r
- if (fHighlightedRank != Long.MIN_VALUE) {\r
- fHighlightedRank = Long.MIN_VALUE;\r
- refreshLineBackgrounds();\r
- }\r
- return;\r
- }\r
- int offset = fStyledText.getOffsetAtLocation(new Point(0, e.y));\r
- int line = fStyledText.getLineAtOffset(offset);\r
- if (line < fLines.size() - fTopLineIndex) {\r
- LineData lineData = fLines.get(fTopLineIndex + line);\r
- if (fHighlightedRank != lineData.rank) {\r
- fHighlightedRank = lineData.rank;\r
- refreshLineBackgrounds();\r
- }\r
- } else {\r
- if (fHighlightedRank != Long.MIN_VALUE) {\r
- fHighlightedRank = Long.MIN_VALUE;\r
- refreshLineBackgrounds();\r
- }\r
- }\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // MouseTrackListener (StyledText)\r
- // ------------------------------------------------------------------------\r
- \r
- @Override\r
- public void mouseExit(MouseEvent e) {\r
- fCursorYCoordinate = -1;\r
- if (fHighlightedRank != Long.MIN_VALUE) {\r
- fHighlightedRank = Long.MIN_VALUE;\r
- refreshLineBackgrounds();\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseEnter(MouseEvent e) {\r
- fCursorYCoordinate = e.y;\r
- }\r
-\r
- @Override\r
- public void mouseHover(MouseEvent e) {\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // MouseWheelListener (StyledText)\r
- // ------------------------------------------------------------------------\r
- \r
- @Override\r
- public void mouseScrolled(MouseEvent e) {\r
- if (fLines.size() == 0) {\r
- return;\r
- }\r
- fHoldSelection++;\r
- fTopLineIndex -= e.count;\r
- loadLineData();\r
- updateTextArea();\r
- fHoldSelection = 0;\r
- //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));\r
- updateHighlightedRank();\r
- fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));\r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.rawviewer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CaretEvent;
+import org.eclipse.swt.custom.CaretListener;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Slider;
+
+/**
+ * TmfRawEventViewer allows for the display of the raw data for an arbitrarily
+ * large number of TMF events.
+ *
+ * It is essentially a Composite of a StyledText area and a Slider, where the number
+ * of visible lines in the StyledText control is set to fill the viewer display area.
+ * An underlying data model is used to store a cache of event raw text line data.
+ * The slider is ratio-based.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class TmfRawEventViewer extends Composite implements ControlListener, SelectionListener,
+ KeyListener, CaretListener, MouseMoveListener, MouseTrackListener, MouseWheelListener {
+
+ private static final Color COLOR_BACKGROUND_ODD = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
+ private static final Color COLOR_BACKGROUND_EVEN = new Color(Display.getDefault(), 242, 242, 242);
+ private static final Color COLOR_BACKGROUND_SELECTED = new Color(Display.getDefault(), 231, 246, 254);
+ private static final Color COLOR_BACKGROUND_HIGHLIGHTED = new Color(Display.getDefault(), 246, 252, 255);
+ private static final int MAX_LINE_DATA_SIZE = 1000;
+ private static final int SLIDER_MAX = 1000000;
+
+ private ITmfTrace fTrace;
+ private ITmfContext fBottomContext;
+
+ private ScrolledComposite fScrolledComposite;
+ private Composite fTextArea;
+ private StyledText fStyledText;
+ private Font fFixedFont;
+ private Slider fSlider;
+
+ private final List<LineData> fLines = new ArrayList<LineData>();
+ private boolean fActualRanks = false;
+ private int fTopLineIndex;
+ private int fLastTopLineIndex;
+ private final CaretPosition[] fStoredCaretPosition = new CaretPosition[]
+ { new CaretPosition(0, 0), new CaretPosition(0,0)};
+ private int fNumVisibleLines;
+ private ITmfLocation fSelectedLocation = null;
+ private long fHighlightedRank = Long.MIN_VALUE;
+ private int fCursorYCoordinate = -1;
+ private int fHoldSelection = 0;
+
+ private static class LineData {
+ long rank;
+ ITmfLocation location;
+ String string;
+ public LineData(long rank, ITmfLocation location, String string) {
+ this.rank = rank;
+ this.location = location;
+ if (string.length() == 0) {
+ this.string = " "; // workaround for setLineBackground has no effect on empty line //$NON-NLS-1$
+ } else {
+ this.string = string;
+ }
+ }
+ @Override
+ public String toString() {
+ return rank + " [" + location + "]: " + string; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ private static class CaretPosition {
+ int time;
+ int caretOffset;
+ public CaretPosition(int time, int caretOffset) {
+ this.time = time;
+ this.caretOffset = caretOffset;
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ * @param parent The parent composite
+ * @param style The style bits
+ */
+ public TmfRawEventViewer(Composite parent, int style) {
+ super(parent, style & (~SWT.H_SCROLL) & (~SWT.V_SCROLL));
+
+ // Set the layout
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 2;
+ gridLayout.horizontalSpacing = 0;
+ gridLayout.verticalSpacing = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.marginHeight = 0;
+ setLayout(gridLayout);
+
+ // Create the controls
+ createTextArea(style & SWT.H_SCROLL);
+ createSlider(style & SWT.V_SCROLL);
+
+ // Prevent the slider from being traversed
+ setTabList(new Control[] { fScrolledComposite });
+ }
+
+ @Override
+ public void dispose() {
+ if (fFixedFont != null) {
+ fFixedFont.dispose();
+ fFixedFont = null;
+ }
+ super.dispose();
+ }
+
+ // ------------------------------------------------------------------------
+ // Text area handling
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create the text area and add listeners
+ */
+ private void createTextArea(int style) {
+ fScrolledComposite = new ScrolledComposite(this, style);
+ fScrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ fTextArea = new Composite(fScrolledComposite, SWT.NONE);
+ fTextArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ fScrolledComposite.setContent(fTextArea);
+ fScrolledComposite.setExpandHorizontal(true);
+ fScrolledComposite.setExpandVertical(true);
+ fScrolledComposite.setAlwaysShowScrollBars(true);
+ fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ fScrolledComposite.addControlListener(this);
+
+ GridLayout textAreaGridLayout = new GridLayout();
+ textAreaGridLayout.marginHeight = 0;
+ textAreaGridLayout.marginWidth = 0;
+ fTextArea.setLayout(textAreaGridLayout);
+
+ if (fFixedFont == null) {
+ if (System.getProperty("os.name").contains("Windows")) { //$NON-NLS-1$ //$NON-NLS-2$
+ fFixedFont = new Font(Display.getCurrent(), new FontData("Courier New", 10, SWT.NORMAL)); //$NON-NLS-1$
+ } else {
+ fFixedFont = new Font(Display.getCurrent(), new FontData("Monospace", 10, SWT.NORMAL)); //$NON-NLS-1$
+ }
+ }
+
+ fStyledText = new StyledText(fTextArea, SWT.READ_ONLY);
+ fStyledText.setFont(fFixedFont);
+ fStyledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+
+ fStyledText.addCaretListener(this);
+ fStyledText.addMouseMoveListener(this);
+ fStyledText.addMouseTrackListener(this);
+ fStyledText.addMouseWheelListener(this);
+ fStyledText.addListener(SWT.MouseWheel, new Listener() { // disable mouse scroll of horizontal scroll bar
+ @Override
+ public void handleEvent(Event event) { event.doit = false; }});
+ fStyledText.addKeyListener(this);
+
+ fTextArea.setBackground(fStyledText.getBackground());
+ fTextArea.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent e) {
+ fTextArea.setFocus();
+ }});
+ }
+
+ // ------------------------------------------------------------------------
+ // Slider handling
+ // ------------------------------------------------------------------------
+
+ private void createSlider(int style) {
+ fSlider = new Slider(this, SWT.VERTICAL);
+ fSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
+ fSlider.setValues(0, 0, SLIDER_MAX, SLIDER_MAX, 1, 1);
+ fSlider.addSelectionListener(this);
+ if ((style & SWT.V_SCROLL) == 0) {
+ fSlider.setVisible(false);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Controls interactions
+ // ------------------------------------------------------------------------
+
+ @Override
+ public boolean setFocus() {
+ boolean isVisible = isVisible();
+ if (isVisible) {
+ fTextArea.setFocus();
+ }
+ return isVisible;
+ }
+
+ @Override
+ public void setMenu(Menu menu) {
+ fStyledText.setMenu(menu);
+ }
+
+ /**
+ * Sets the trace and updates the content
+ * @param trace The trace to set
+ */
+ public void setTrace(ITmfTrace trace) {
+ fTrace = trace;
+ fTopLineIndex = 0;
+ fLines.clear();
+ refreshEventCount();
+ }
+
+ /**
+ * Refreshes the event count, updates the slider thumb and loads display
+ */
+ public void refreshEventCount() {
+ if (fTrace != null) {
+ if (fTrace.getNbEvents() > 0) {
+ fSlider.setThumb((int) Math.max(SLIDER_MAX / fTrace.getNbEvents(), 1));
+ } else {
+ fSlider.setThumb(SLIDER_MAX);
+ }
+
+ if (!isVisible()) {
+ return;
+ }
+
+ if (fLines.size() == 0) {
+ setTopRank(0);
+ } else if (fLines.size() < fNumVisibleLines) {
+ fBottomContext = null;
+ loadLineData();
+ fillTextArea();
+ //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
+ fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
+ }
+ } else {
+ fBottomContext = null;
+ fillTextArea();
+ fSlider.setThumb(SLIDER_MAX);
+ fSlider.setSelection(0);
+ }
+ }
+
+ /**
+ * Selects the event of given rank and makes it visible.
+ * @param rank The rank of event
+ */
+ public void selectAndReveal(long rank) {
+ if (fTrace == null || !isVisible()) {
+ return;
+ }
+ if (fActualRanks && fTopLineIndex < fLines.size() && rank >= fLines.get(fTopLineIndex).rank) {
+ int lastVisibleIndex = Math.min(fTopLineIndex + fNumVisibleLines, fLines.size()) - 1;
+ if (rank <= fLines.get(lastVisibleIndex).rank) {
+ for (int i = fTopLineIndex; i < fLines.size(); i++) {
+ if (fLines.get(i).rank == rank) {
+ fSelectedLocation = fLines.get(i).location;
+ break;
+ }
+ }
+ refreshLineBackgrounds();
+ return;
+ }
+ }
+ setTopRank(rank);
+ if (fLines.size() > 0 && fHoldSelection == 0) {
+ fSelectedLocation = fLines.get(0).location;
+ refreshLineBackgrounds();
+ }
+ }
+
+ /**
+ * Add a selection listener
+ * @param listener A listener to add
+ */
+ public void addSelectionListener(Listener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ }
+ addListener (SWT.Selection, listener);
+ }
+
+ /**
+ * Remove selection listener
+ * @param listener A listener to remove
+ */
+ public void removeSelectionListener(Listener listener) {
+ checkWidget();
+ if (listener == null) {
+ SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ }
+ removeListener(SWT.Selection, listener);
+ }
+
+ private void sendSelectionEvent(LineData lineData) {
+ Event event = new Event();
+ if (fActualRanks) {
+ event.data = Long.valueOf(lineData.rank);
+ } else {
+ event.data = lineData.location;
+ }
+ notifyListeners(SWT.Selection, event);
+ }
+
+ private void setTopRank(long rank) {
+ fBottomContext = fTrace.seekEvent(rank);
+ if (fBottomContext == null) {
+ return;
+ }
+ fLines.clear();
+ fActualRanks = true;
+ fTopLineIndex = 0;
+ loadLineData();
+ refreshTextArea();
+ if (fLines.size() == 0) {
+ fSlider.setSelection(0);
+ } else {
+ //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
+ fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
+ }
+ }
+
+ private void setTopPosition(double ratio) {
+ fBottomContext = fTrace.seekEvent(ratio);
+ if (fBottomContext == null) {
+ return;
+ }
+ fBottomContext.setRank(0);
+ fLines.clear();
+ fActualRanks = false;
+ fTopLineIndex = 0;
+ loadLineData();
+ refreshTextArea();
+ }
+
+ private void loadLineData() {
+ if (fTopLineIndex < 0) {
+ //if (fLines.size() > 0 && fLines.get(0).rank > 0) {
+ //long endRank = fLines.get(0).rank;
+ //long startRank = Math.max(0, endRank - fNumVisibleLines);
+ //TmfContext context = fTrace.seekEvent(startRank);
+ //int index = 0;
+ //while (context.getRank() < endRank) {
+ //long rank = context.getRank();
+ //ITmfLocation<?> location = context.getLocation();
+ //TmfEvent event = fTrace.getNextEvent(context);
+ //String[] lines = event.getRawText().split("\r?\n");
+ //for (int i = 0; i < lines.length; i++) {
+ //String line = lines[i];
+ //LineData lineData = new LineData(rank, location, line);
+ //fLines.add(index++, lineData);
+ //fTopLineIndex++;
+ //fLastTopLineIndex++;
+ //}
+ //}
+ //}
+ if (fLines.size() > 0 && fTrace.getLocationRatio(fLines.get(0).location) > 0) {
+ double lastRatio = fTrace.getLocationRatio(fLines.get(fLines.size() - 1).location);
+ double firstRatio = fTrace.getLocationRatio(fLines.get(0).location);
+ double delta;
+ boolean singleEvent = false;
+ if (firstRatio != lastRatio) {
+ // approximate ratio of at least 20 items
+ delta = Math.max(20, fNumVisibleLines) * (lastRatio - firstRatio) / (fLines.size() - 1);
+ } else {
+ delta = Math.pow(10, -15);
+ singleEvent = true;
+ }
+ while (fTopLineIndex < 0) {
+ ITmfLocation endLocation = fLines.get(0).location;
+ firstRatio = Math.max(0, firstRatio - delta);
+ ITmfContext context = fTrace.seekEvent(firstRatio);
+ ITmfLocation location;
+ int index = 0;
+ long rank = 0;
+ while (!context.getLocation().equals(endLocation)) {
+ location = context.getLocation().clone();
+ ITmfEvent event = fTrace.getNext(context);
+ if (event == null) {
+ break;
+ }
+ if (event.getContent() != null && event.getContent().getValue() != null) {
+ String[] lines = event.getContent().getValue().toString().split("\r?\n"); //$NON-NLS-1$
+ for (int i = 0; i < lines.length; i++) {
+ String line = lines[i];
+ LineData lineData = new LineData(rank, location, line);
+ fLines.add(index++, lineData);
+ fTopLineIndex++;
+ fLastTopLineIndex++;
+ }
+ } else {
+ LineData lineData = new LineData(rank, location, ""); //$NON-NLS-1$
+ fLines.add(index++, lineData);
+ fTopLineIndex++;
+ fLastTopLineIndex++;
+ }
+ rank++;
+ }
+ long rankOffset = fLines.get(index).rank - rank;
+ for (int i = 0; i < index; i++) {
+ fLines.get(i).rank += rankOffset;
+ }
+ if (firstRatio == 0) {
+ break;
+ }
+ if (singleEvent) {
+ delta = Math.min(delta * 10, 0.1);
+ }
+ }
+ }
+ if (fTopLineIndex < 0) {
+ fTopLineIndex = 0;
+ }
+ }
+
+ while (fLines.size() - fTopLineIndex < fNumVisibleLines) {
+ if (fBottomContext == null) {
+ if (fLines.size() == 0) {
+ fBottomContext = fTrace.seekEvent(0);
+ } else {
+ //fBottomContext = fTrace.seekEvent(fLines.get(fLines.size() - 1).rank + 1);
+ fBottomContext = fTrace.seekEvent(fLines.get(fLines.size() - 1).location);
+ fTrace.getNext(fBottomContext);
+ }
+ if (fBottomContext == null) {
+ break;
+ }
+ }
+ long rank = fBottomContext.getRank();
+ ITmfLocation location = fBottomContext.getLocation() != null ? fBottomContext.getLocation().clone() : null;
+ ITmfEvent event = fTrace.getNext(fBottomContext);
+ if (event == null) {
+ break;
+ }
+ if (event.getContent() != null && event.getContent().getValue() != null) {
+ for (String line : event.getContent().getValue().toString().split("\r?\n")) { //$NON-NLS-1$
+ int crPos;
+ if ((crPos = line.indexOf('\r')) != -1) {
+ line = line.substring(0, crPos);
+ }
+ LineData lineData = new LineData(rank, location, line);
+ fLines.add(lineData);
+ }
+ } else {
+ LineData lineData = new LineData(rank, location, ""); //$NON-NLS-1$
+ fLines.add(lineData);
+ }
+ }
+ fTopLineIndex = Math.max(0, Math.min(fTopLineIndex, fLines.size() - 1));
+
+ if (fLines.size() > MAX_LINE_DATA_SIZE) {
+ if (fTopLineIndex < MAX_LINE_DATA_SIZE / 2) {
+ long rank = fLines.get(MAX_LINE_DATA_SIZE - 1).rank;
+ for (int i = MAX_LINE_DATA_SIZE; i < fLines.size(); i++) {
+ if (fLines.get(i).rank > rank) {
+ fLines.subList(i, fLines.size()).clear();
+ fBottomContext = null;
+ break;
+ }
+ }
+ } else {
+ long rank = fLines.get(fLines.size() - MAX_LINE_DATA_SIZE).rank;
+ for (int i = fLines.size() - MAX_LINE_DATA_SIZE - 1; i >= 0; i--) {
+ if (fLines.get(i).rank < rank) {
+ fLines.subList(0, i + 1).clear();
+ fTopLineIndex -= (i + 1);
+ fLastTopLineIndex -= (i + 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private void refreshTextArea() {
+ fStyledText.setText(""); //$NON-NLS-1$
+ for (int i = 0; i < fLines.size() - fTopLineIndex && i < fNumVisibleLines; i++) {
+ if (i > 0)
+ {
+ fStyledText.append("\n"); //$NON-NLS-1$
+ }
+ LineData lineData = fLines.get(fTopLineIndex + i);
+ fStyledText.append(lineData.string);
+ setLineBackground(i, lineData);
+ }
+ fTextArea.layout();
+ fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ fLastTopLineIndex = fTopLineIndex;
+ }
+
+ private void fillTextArea() {
+ int nextLine = fStyledText.getCharCount() == 0 ? 0 : fStyledText.getLineCount();
+ for (int i = nextLine; i < fLines.size() - fTopLineIndex && i < fNumVisibleLines; i++) {
+ if (i > 0)
+ {
+ fStyledText.append("\n"); //$NON-NLS-1$
+ }
+ LineData lineData = fLines.get(fTopLineIndex + i);
+ fStyledText.append(lineData.string);
+ setLineBackground(i, lineData);
+ }
+ int endLine = Math.min(fNumVisibleLines, fLines.size());
+ if (endLine < fStyledText.getLineCount()) {
+ int endOffset = fStyledText.getOffsetAtLine(endLine) - 1;
+ if (endOffset > fStyledText.getCharCount()) {
+ fHoldSelection++;
+ fStyledText.replaceTextRange(endOffset, fStyledText.getCharCount() - endOffset, ""); //$NON-NLS-1$
+ fHoldSelection--;
+ }
+ }
+ fTextArea.layout();
+ fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ }
+
+ private void updateTextArea() {
+ if (fTopLineIndex < fLastTopLineIndex) {
+ StringBuffer insertedText = new StringBuffer();
+ for (int i = fTopLineIndex; i < fLastTopLineIndex; i++) {
+ insertedText.append(fLines.get(i).string + "\n"); //$NON-NLS-1$
+ }
+ fStyledText.replaceTextRange(0, 0, insertedText.toString());
+ for (int i = 0; i < fLastTopLineIndex - fTopLineIndex; i++) {
+ LineData lineData = fLines.get(fTopLineIndex + i);
+ setLineBackground(i, lineData);
+ }
+ fLastTopLineIndex = fTopLineIndex;
+ } else if (fTopLineIndex > fLastTopLineIndex) {
+ int length = 0;
+ for (int i = 0; i < fTopLineIndex - fLastTopLineIndex && i < fNumVisibleLines; i++) {
+ length += fLines.get(i + fLastTopLineIndex).string.length();
+ if (i < fStyledText.getLineCount()) {
+ length += 1;
+ }
+ }
+ fStyledText.replaceTextRange(0, length, ""); //$NON-NLS-1$
+ fLastTopLineIndex = fTopLineIndex;
+ fillTextArea();
+ }
+ int endLine = Math.min(fNumVisibleLines, fLines.size());
+ if (endLine < fStyledText.getLineCount()) {
+ int endOffset = fStyledText.getOffsetAtLine(endLine) - 1;
+ if (endOffset > fStyledText.getCharCount()) {
+ fStyledText.replaceTextRange(endOffset, fStyledText.getCharCount() - endOffset, ""); //$NON-NLS-1$
+ }
+ }
+ fTextArea.layout();
+ fScrolledComposite.setMinSize(fTextArea.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ }
+
+ private void refreshLineBackgrounds() {
+ for (int i = 0; (i < fStyledText.getLineCount()) && (i < fNumVisibleLines) && (i < fLines.size() - fTopLineIndex); i++) {
+ LineData lineData = fLines.get(fTopLineIndex + i);
+ setLineBackground(i, lineData);
+ }
+ }
+
+ private void setLineBackground(int index, LineData lineData) {
+ if (lineData.location.equals(fSelectedLocation)) {
+ fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_SELECTED);
+ } else if (lineData.rank == fHighlightedRank) {
+ fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_HIGHLIGHTED);
+ } else if (lineData.rank % 2 == 0) {
+ fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_EVEN);
+ } else {
+ fStyledText.setLineBackground(index, 1, COLOR_BACKGROUND_ODD);
+ }
+ }
+
+ private void storeCaretPosition(int time, int caretOffset) {
+ if (fStoredCaretPosition[0].time == time) {
+ fStoredCaretPosition[0].caretOffset = caretOffset;
+ } else {
+ fStoredCaretPosition[1] = fStoredCaretPosition[0];
+ fStoredCaretPosition[0] = new CaretPosition(time, caretOffset);
+ }
+ }
+
+ private int getPreviousCaretOffset(int time) {
+ if (fStoredCaretPosition[0].time == time) {
+ return fStoredCaretPosition[1].caretOffset;
+ }
+ return fStoredCaretPosition[0].caretOffset;
+ }
+
+ private void updateHighlightedRank() {
+ if (fCursorYCoordinate < 0 || fCursorYCoordinate > fStyledText.getSize().y) {
+ if (fHighlightedRank != Long.MIN_VALUE) {
+ fHighlightedRank = Long.MIN_VALUE;
+ refreshLineBackgrounds();
+ }
+ return;
+ }
+ int offset = fStyledText.getOffsetAtLocation(new Point(0, fCursorYCoordinate));
+ int line = fStyledText.getLineAtOffset(offset);
+ if (line < fLines.size() - fTopLineIndex) {
+ LineData lineData = fLines.get(fTopLineIndex + line);
+ if (fHighlightedRank != lineData.rank) {
+ fHighlightedRank = lineData.rank;
+ refreshLineBackgrounds();
+ }
+ } else {
+ if (fHighlightedRank != Long.MIN_VALUE) {
+ fHighlightedRank = Long.MIN_VALUE;
+ refreshLineBackgrounds();
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // ControlListener (ScrolledComposite)
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void controlResized(ControlEvent event) {
+ int areaHeight = fScrolledComposite.getSize().y;
+ if (fScrolledComposite.getHorizontalBar() != null) {
+ areaHeight -= fScrolledComposite.getHorizontalBar().getSize().y;
+ }
+ int lineHeight = fStyledText.getLineHeight();
+ fNumVisibleLines = Math.max((areaHeight + lineHeight - 1) / lineHeight, 1);
+
+ if (fBottomContext != null) {
+ loadLineData();
+ fillTextArea();
+ }
+ }
+
+ @Override
+ public void controlMoved(ControlEvent e) {
+ }
+
+ // ------------------------------------------------------------------------
+ // SelectionListener (Slider)
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fTextArea.setFocus();
+ if (fLines.size() == 0) {
+ return;
+ }
+ if (e.detail == SWT.DRAG) {
+ return;
+ }
+ fHoldSelection++;
+ switch (e.detail) {
+ case SWT.NONE: {
+ //long rank = (long) (fTrace.getNbEvents() * ((double) fSlider.getSelection() / SLIDER_MAX));
+ //setTopRank(rank);
+ if (fSlider.getSelection() == 0 || fSlider.getThumb() == SLIDER_MAX) {
+ fLines.clear();
+ setTopPosition(0.0);
+ break;
+ }
+ double ratio = (double) fSlider.getSelection() / (SLIDER_MAX - fSlider.getThumb());
+ double delta = Math.pow(10, -15);
+ fLines.clear();
+ while (fLines.size() == 0) {
+ setTopPosition(ratio);
+ if (ratio == 0.0) {
+ break;
+ }
+ delta = Math.min(delta * 10, 0.1);
+ ratio = Math.max(ratio - delta, 0.0);
+ }
+ break;
+ }
+ case SWT.ARROW_DOWN: {
+ if (fTopLineIndex >= fLines.size()) {
+ break;
+ }
+ fTopLineIndex++;
+ loadLineData();
+ updateTextArea();
+ break;
+ }
+ case SWT.PAGE_DOWN: {
+ fTopLineIndex += Math.max(fNumVisibleLines - 1, 1);
+ loadLineData();
+ updateTextArea();
+ break;
+ }
+ case SWT.ARROW_UP: {
+ //if (fLines.size() == 0 || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
+ if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
+ break;
+ }
+ fTopLineIndex--;
+ loadLineData();
+ updateTextArea();
+ break;
+ }
+ case SWT.PAGE_UP: {
+ fTopLineIndex -= Math.max(fNumVisibleLines - 1, 1);
+ loadLineData();
+ updateTextArea();
+ break;
+ }
+ case SWT.HOME: {
+ //selectAndReveal(0);
+ setTopPosition(0.0);
+ break;
+ }
+ case SWT.END: {
+ //if (fTrace.getNbEvents() > 0) {
+ //selectAndReveal(fTrace.getNbEvents() - 1);
+ //}
+ double ratio = 1.0;
+ double delta = Math.pow(10, -15);
+ fLines.clear();
+ while (fLines.size() == 0) {
+ setTopPosition(ratio);
+ if (ratio == 0.0) {
+ break;
+ }
+ delta = Math.min(delta * 10, 0.1);
+ ratio = Math.max(ratio - delta, 0.0);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
+ if (e.detail != SWT.NONE) {
+ fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
+ }
+
+ fHoldSelection = 0;
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+
+ // ------------------------------------------------------------------------
+ // KeyListener (StyledText)
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (fLines.size() == 0) {
+ return;
+ }
+ int caretOffset = fStyledText.getCaretOffset();
+ int previousCaretOffset = getPreviousCaretOffset(e.time);
+ int previousLineAtCaretPosition = fStyledText.getLineAtOffset(previousCaretOffset);
+ int previousColumnAtCaretPosition = getPreviousCaretOffset(e.time) - fStyledText.getOffsetAtLine(previousLineAtCaretPosition);
+ switch (e.keyCode) {
+ case SWT.ARROW_DOWN: {
+ if (previousLineAtCaretPosition < (fNumVisibleLines - 2)) {
+ break;
+ }
+ fHoldSelection++;
+ fTopLineIndex++;
+ loadLineData();
+ updateTextArea();
+ fHoldSelection--;
+ LineData lineData = fLines.get(fTopLineIndex + fStyledText.getLineAtOffset(fStyledText.getCaretOffset()));
+ if (!lineData.location.equals(fSelectedLocation)) {
+ fSelectedLocation = lineData.location;
+ refreshLineBackgrounds();
+ sendSelectionEvent(lineData);
+ }
+ break;
+ }
+ case SWT.PAGE_DOWN: {
+ if (previousLineAtCaretPosition >= (fNumVisibleLines - 1)) {
+ fHoldSelection++;
+ if (fLines.get(fTopLineIndex + previousLineAtCaretPosition).rank % 2 == 0) {
+ fStyledText.setLineBackground(previousLineAtCaretPosition, 1, COLOR_BACKGROUND_EVEN);
+ } else {
+ fStyledText.setLineBackground(previousLineAtCaretPosition, 1, COLOR_BACKGROUND_ODD);
+ }
+ fSelectedLocation = null;
+ fTopLineIndex += Math.max(fNumVisibleLines - 1, 1);
+ loadLineData();
+ updateTextArea();
+ fHoldSelection--;
+ }
+ int line = Math.min(fNumVisibleLines - 1, fStyledText.getLineCount() - 1);
+ int offset = fStyledText.getOffsetAtLine(line);
+ fStyledText.setSelection(offset + Math.min(previousColumnAtCaretPosition, fLines.get(fTopLineIndex + line).string.length()));
+ break;
+ }
+ case SWT.ARROW_RIGHT: {
+ if (previousCaretOffset < fStyledText.getCharCount() || previousLineAtCaretPosition < (fNumVisibleLines - 2)) {
+ break;
+ }
+ fHoldSelection++;
+ fTopLineIndex++;
+ loadLineData();
+ updateTextArea();
+ fHoldSelection--;
+ fStyledText.setSelection(fStyledText.getCaretOffset() + 1);
+ break;
+ }
+ case SWT.ARROW_UP: {
+ if (previousLineAtCaretPosition > 0) {
+ break;
+ }
+ if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
+ break;
+ }
+ fHoldSelection++;
+ fTopLineIndex--;
+ loadLineData();
+ updateTextArea();
+ fHoldSelection--;
+ LineData lineData = fLines.get(fTopLineIndex);
+ if (!lineData.location.equals(fSelectedLocation)) {
+ fSelectedLocation = lineData.location;
+ refreshLineBackgrounds();
+ sendSelectionEvent(lineData);
+ }
+ fStyledText.setSelection(caretOffset);
+ break;
+ }
+ case SWT.PAGE_UP: {
+ if (previousLineAtCaretPosition > 0) {
+ break;
+ }
+ fHoldSelection++;
+ fTopLineIndex -= Math.max(fNumVisibleLines - 1, 1);
+ loadLineData();
+ updateTextArea();
+ fHoldSelection--;
+ LineData lineData = fLines.get(fTopLineIndex);
+ if (!lineData.location.equals(fSelectedLocation)) {
+ fSelectedLocation = lineData.location;
+ refreshLineBackgrounds();
+ sendSelectionEvent(lineData);
+ }
+ fStyledText.setSelection(caretOffset);
+ break;
+ }
+ case SWT.ARROW_LEFT: {
+ if (previousCaretOffset > 0) {
+ break;
+ }
+ if (fLines.size() == 0) {// || (fTopLineIndex == 0 && fLines.get(0).rank == 0)) {
+ break;
+ }
+ long topRank = fLines.get(fTopLineIndex).rank;
+ fHoldSelection++;
+ fTopLineIndex--;
+ loadLineData();
+ updateTextArea();
+ fHoldSelection--;
+ LineData lineData = fLines.get(fTopLineIndex);
+ if (!lineData.location.equals(fSelectedLocation)) {
+ fSelectedLocation = lineData.location;
+ refreshLineBackgrounds();
+ sendSelectionEvent(lineData);
+ }
+ if (topRank != fLines.get(fTopLineIndex).rank) {
+ fStyledText.setSelection(fLines.get(fTopLineIndex).string.length());
+ }
+ break;
+ }
+ case SWT.HOME: {
+ if ((e.stateMask & SWT.CTRL) == 0) {
+ break;
+ }
+ //selectAndReveal(0);
+ setTopPosition(0.0);
+ LineData lineData = fLines.get(fTopLineIndex);
+ if (!lineData.location.equals(fSelectedLocation)) {
+ fSelectedLocation = lineData.location;
+ refreshLineBackgrounds();
+ sendSelectionEvent(lineData);
+ }
+ break;
+ }
+ case SWT.END: {
+ if ((e.stateMask & SWT.CTRL) == 0) {
+ break;
+ }
+ //if (fTrace.getNbEvents() > 0) {
+ //selectAndReveal(fTrace.getNbEvents() - 1);
+ //}
+ double ratio = 1.0;
+ double delta = Math.pow(10, -15);
+ fLines.clear();
+ while (fLines.size() == 0) {
+ setTopPosition(ratio);
+ if (ratio == 0.0) {
+ break;
+ }
+ delta = Math.min(delta * 10, 0.1);
+ ratio = Math.max(ratio - delta, 0.0);
+ }
+ LineData lineData = fLines.get(fTopLineIndex);
+ if (!lineData.location.equals(fSelectedLocation)) {
+ fSelectedLocation = lineData.location;
+ refreshLineBackgrounds();
+ sendSelectionEvent(lineData);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
+ updateHighlightedRank();
+ fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ // ------------------------------------------------------------------------
+ // CaretListener (StyledText)
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void caretMoved(CaretEvent event) {
+ if (fHoldSelection == 0) {
+ int line = fStyledText.getLineAtOffset(event.caretOffset);
+ if (fTopLineIndex + line < fLines.size()) {
+ LineData lineData = fLines.get(fTopLineIndex + line);
+ if (!lineData.location.equals(fSelectedLocation)) {
+ fSelectedLocation = lineData.location;
+ refreshLineBackgrounds();
+ sendSelectionEvent(lineData);
+ }
+ }
+ }
+ storeCaretPosition(event.time, event.caretOffset);
+ if (fHoldSelection == 0) {
+ Point caret = fStyledText.getLocationAtOffset(fStyledText.getCaretOffset());
+ Point origin = fScrolledComposite.getOrigin();
+ if (origin.x > caret.x) {
+ origin.x = caret.x;
+ } else if (caret.x - origin.x > fScrolledComposite.getSize().x) {
+ origin.x = caret.x - fScrolledComposite.getSize().x + 1;
+ }
+ fScrolledComposite.setOrigin(origin);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseMoveListener (StyledText)
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseMove(MouseEvent e) {
+ fCursorYCoordinate = e.y;
+ if (e.y < 0 || e.y > fStyledText.getSize().y) {
+ if (fHighlightedRank != Long.MIN_VALUE) {
+ fHighlightedRank = Long.MIN_VALUE;
+ refreshLineBackgrounds();
+ }
+ return;
+ }
+ int offset = fStyledText.getOffsetAtLocation(new Point(0, e.y));
+ int line = fStyledText.getLineAtOffset(offset);
+ if (line < fLines.size() - fTopLineIndex) {
+ LineData lineData = fLines.get(fTopLineIndex + line);
+ if (fHighlightedRank != lineData.rank) {
+ fHighlightedRank = lineData.rank;
+ refreshLineBackgrounds();
+ }
+ } else {
+ if (fHighlightedRank != Long.MIN_VALUE) {
+ fHighlightedRank = Long.MIN_VALUE;
+ refreshLineBackgrounds();
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseTrackListener (StyledText)
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseExit(MouseEvent e) {
+ fCursorYCoordinate = -1;
+ if (fHighlightedRank != Long.MIN_VALUE) {
+ fHighlightedRank = Long.MIN_VALUE;
+ refreshLineBackgrounds();
+ }
+ }
+
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ fCursorYCoordinate = e.y;
+ }
+
+ @Override
+ public void mouseHover(MouseEvent e) {
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseWheelListener (StyledText)
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseScrolled(MouseEvent e) {
+ if (fLines.size() == 0) {
+ return;
+ }
+ fHoldSelection++;
+ fTopLineIndex -= e.count;
+ loadLineData();
+ updateTextArea();
+ fHoldSelection = 0;
+ //fSlider.setSelection((int) (SLIDER_MAX * ((double) fLines.get(fTopLineIndex).rank / fTrace.getNbEvents())));
+ updateHighlightedRank();
+ fSlider.setSelection((int) (SLIDER_MAX * fTrace.getLocationRatio(fLines.get(fTopLineIndex).location)));
+ }
+
+}