/******************************************************************************* * Copyright (c) 2013 Red Hat Inc. * 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: * Red Hat Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.linuxtools.internal.perf.ui; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.IFindReplaceTarget; import org.eclipse.linuxtools.internal.perf.IPerfData; import org.eclipse.linuxtools.internal.perf.PerfPlugin; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.texteditor.FindReplaceAction; /** * A ViewPart to display the output from perf's source disassembly. */ public class SourceDisassemblyView extends ViewPart implements IFindReplaceTarget{ private static final Color RED = new Color(Display.getDefault(), 150, 0, 0); private static final Color ORANGE = new Color(Display.getDefault(), 150, 100, 0); private static final Color GREEN = new Color(Display.getDefault(), 0, 100, 0); private static String ASM = "\\s+([0-9]+\\.[0-9]+ )?:\\s+[0-9a-f]+:\\s+[0-9a-z]+\\s+.*"; //$NON-NLS-1$ private static String CODE = "\\s+:\\s+.*"; //$NON-NLS-1$ private static String WORD_BOUNDARY = "\\b"; //$NON-NLS-1$' private static int SECONDARY_ID = 0; private StyledText text; public SourceDisassemblyView() { } @Override public void createPartControl(Composite parent) { parent.setLayoutData(new GridLayout(1, true)); text = new StyledText(parent, SWT.WRAP | SWT.V_SCROLL); text.setEditable(false); IPerfData data = PerfPlugin.getDefault().getSourceDisassemblyData(); if (data != null) { setStyledText(data.getPerfData()); setContentDescription(data.getTitle()); setupFindDialog(); } } @Override public void setFocus() { return; } /** * Set styled text field (only used for testing). * * @param txt StyledText to set. */ protected void setStyledText(StyledText txt) { text = txt; } /** * Get the text content of this view. * * @return String content of this view */ public String getContent() { return (text == null) ? "" : text.getText(); //$NON-NLS-1$ } /** * Set styled text field based on the specified string, which is parsed in * order to set appropriate styles to be used for rendering the widget * content. * * @param input text content of widget. */ private void setStyledText (String input) { List<StyleRange> styles = new ArrayList<> (); int ptr = 0; text.setText(input); StringTokenizer tok = new StringTokenizer(input, "\n"); //$NON-NLS-1$ while (tok.hasMoreTokens()) { String line = tok.nextToken(); if (Pattern.matches(ASM, line)) { Matcher m = Pattern.compile(ASM).matcher(line); if (m.matches() && m.group(1) != null) { try { float percent = Float.parseFloat(m.group(1).trim()); if (percent >= 20) { styles.add(new StyleRange(ptr, line.length(), RED, null)); } else if (percent >= 5) { styles.add(new StyleRange(ptr, line.length(), ORANGE, null)); } } catch (NumberFormatException e) { // set no StyleRange } } } else if (Pattern.matches(CODE, line)) { styles.add(new StyleRange(ptr, line.length(), GREEN, null)); } // + 1 to skip over the '\n' at EOL that the tokenizer eats ptr += line.length() + 1; } text.setStyleRanges(styles.toArray(new StyleRange [0])); } public static void refreshView () { Display.getDefault().syncExec(() -> { try { // A new view is created every time PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() .showView(PerfPlugin.SOURCE_DISASSEMBLY_VIEW_ID, Integer.toString(SECONDARY_ID++), IWorkbenchPage.VIEW_CREATE); } catch (PartInitException e) { IStatus status = new Status(IStatus.ERROR, PerfPlugin.PLUGIN_ID, e.getMessage(), e); PerfPlugin.getDefault().getLog().log(status); } }); } /** * Create find dialog and set is as a toolbar action. */ private void setupFindDialog() { FindReplaceAction findAction = new FindReplaceAction( Platform.getResourceBundle(PerfPlugin.getDefault().getBundle()), null, text.getShell(), this); findAction.setImageDescriptor(PerfPlugin .getImageDescriptor("icons/search.gif"));//$NON-NLS-1$ findAction.setToolTipText(PerfPlugin.STRINGS_SearchSourceDisassembly); IActionBars bars = getViewSite().getActionBars(); bars.getToolBarManager().add(findAction); bars.setGlobalActionHandler(ActionFactory.FIND.getId(), findAction); } @Override public boolean canPerformFind() { return text != null && !text.getText().isEmpty(); } @Override public int findAndSelect(int widgetOffset, String findString, boolean searchForward, boolean caseSensitive, boolean wholeWord) { int matchIndex = -1; String searchString = text.getText(); String findRegex = findString; // offset is -1 when text boundaries are reached during a wrapped search if (widgetOffset < 0) { widgetOffset = searchForward ? 0 : searchString.length(); } if (wholeWord) { findRegex = WORD_BOUNDARY + findRegex + WORD_BOUNDARY; } int caseFlag = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE; Pattern pattern = Pattern.compile(findRegex, caseFlag); Matcher matcher = pattern.matcher(searchString); if (searchForward) { matchIndex = matcher.find(widgetOffset) ? matcher.start() : -1; } else { // backward search from 0 to offset (exclusive) matcher.region(0, widgetOffset); // get start index of last match while (matcher.find()) { matchIndex = matcher.start(); } } // only select when a match has been found if (matchIndex != -1) { text.setSelection(matchIndex, matchIndex + findString.length()); } return matchIndex; } @Override public Point getSelection() { Point selection = text.getSelection(); // selection point consists of starting point x and lenght y - x. return new Point(selection.x, selection.y - selection.x); } @Override public String getSelectionText() { return text.getSelectionText(); } @Override public boolean isEditable() { return false; } @Override public void replaceSelection(String text) { } }