Package org.adoptopenjdk.jitwatch.ui.triview

Source Code of org.adoptopenjdk.jitwatch.ui.triview.Viewer

/*
* Copyright (c) 2013, 2014 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.ui.triview;

import javafx.scene.layout.VBox;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.adoptopenjdk.jitwatch.model.IMetaMember;
import org.adoptopenjdk.jitwatch.model.LineAnnotation;
import org.adoptopenjdk.jitwatch.ui.IStageAccessProxy;
import org.adoptopenjdk.jitwatch.ui.triview.ILineListener.LineType;
import org.adoptopenjdk.jitwatch.ui.triview.bytecode.BytecodeLabel;
import org.adoptopenjdk.jitwatch.util.ParseUtil;
import org.adoptopenjdk.jitwatch.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;

public class Viewer extends VBox
{
  private ScrollPane scrollPane;
  protected VBox vBoxRows;

  public static final String COLOUR_BLACK = "black";
  public static final String COLOUR_RED = "red";
  public static final String COLOUR_GREEN = "green";
  public static final String COLOUR_BLUE = "blue";

  private int scrollIndex = 0;
  protected int lastScrollIndex = -1;
  protected String originalSource;

  private boolean keyboardMode = false;

  private static final String FONT_STYLE = "-fx-font-family:monospace; -fx-font-size:12px;";
 
  protected static final String STYLE_UNHIGHLIGHTED = FONT_STYLE + "-fx-background-color:white;";
  protected static final String STYLE_HIGHLIGHTED = FONT_STYLE + "-fx-background-color:red;";
  protected static final String STYLE_UNHIGHLIGHTED_SUGGESTION = FONT_STYLE + "-fx-background-color:yellow;";
 
  protected Map<Integer, LineAnnotation> lineAnnotations = new HashMap<>();

  protected static final Logger logger = LoggerFactory.getLogger(Viewer.class);

  protected IStageAccessProxy stageAccessProxy;

  protected ILineListener lineListener;
  protected LineType lineType;

  private boolean isHighlighting;

  public Viewer(IStageAccessProxy stageAccessProxy, boolean highlighting)
  {
    this.stageAccessProxy = stageAccessProxy;
    this.isHighlighting = highlighting;

    lineListener = new NoOpLineListener();

    setup();
  }

  public Viewer(IStageAccessProxy stageAccessProxy, ILineListener lineListener, LineType lineType, boolean highlighting)
  {
    this.stageAccessProxy = stageAccessProxy;
    this.lineListener = lineListener;
    this.lineType = lineType;
    this.isHighlighting = highlighting;

    setup();
  }

  private void setup()
  {
    vBoxRows = new VBox();

    vBoxRows.heightProperty().addListener(new ChangeListener<Number>()
    {
      @Override
      public void changed(ObservableValue<? extends Number> arg0, Number oldValue, Number newValue)
      {
        setScrollBar();
      }
    });

    scrollPane = new ScrollPane();
    scrollPane.setContent(vBoxRows);
    scrollPane.setStyle("-fx-background:white");

    scrollPane.setFitToHeight(true);

    scrollPane.prefHeightProperty().bind(heightProperty());

    EventHandler<KeyEvent> keyHandler = new EventHandler<KeyEvent>()
    {
      @Override
      public void handle(KeyEvent event)
      {
        KeyCode code = event.getCode();

        keyboardMode = true;
        clearAllHighlighting();

        switch (code)
        {
        case UP:
          handleKeyUp();
          break;
        case DOWN:
          handleKeyDown();
          break;
        case LEFT:
          handleKeyLeft();
          break;
        case RIGHT:
          handleKeyRight();
          break;
        case PAGE_UP:
          handleKeyPageUp();
          break;
        case PAGE_DOWN:
          handleKeyPageDown();
          break;
        default:
          break;
        }
      }
    };

    focusedProperty().addListener(new ChangeListener<Boolean>()
    {
      @Override
      public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean hasFocus)
      {
        if (hasFocus)
        {
          scrollPane.requestFocus();
        }
      }
    });

    scrollPane.focusedProperty().addListener(new ChangeListener<Boolean>()
    {
      @Override
      public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean hasFocus)
      {
        if (hasFocus)
        {
          lineListener.lineHighlighted(scrollIndex, lineType);
          highlightLine(scrollIndex);
        }
      }
    });

    scrollPane.setOnMouseEntered(new EventHandler<MouseEvent>()
    {
      @Override
      public void handle(MouseEvent arg0)
      {
        lineListener.handleFocusSelf(lineType);
      }
    });

    scrollPane.setOnKeyPressed(keyHandler);

    getChildren().add(scrollPane);

    setUpContextMenu();
  }

  public void setContent(String inSource, boolean showLineNumbers)
  {
    String source = inSource;
    lineAnnotations.clear();
    lastScrollIndex = -1;

    if (source == null)
    {
      source = "Empty";
    }

    originalSource = source;

    source = source.replace(S_TAB, S_DOUBLE_SPACE);

    String[] lines = source.split(S_NEWLINE);

    int maxWidth = Integer.toString(lines.length).length();

    List<Label> labels = new ArrayList<>();

    for (int i = 0; i < lines.length; i++)
    {
      String row = lines[i];

      if (showLineNumbers)
      {
        lines[i] = StringUtil.padLineNumber(i + 1, maxWidth) + S_DOUBLE_SPACE + row;
      }

      Label lblLine = new Label(lines[i]);

      lblLine.setStyle(STYLE_UNHIGHLIGHTED);
      labels.add(lblLine);
    }

    setContent(labels);
  }

  public void setContent(List<Label> items)
  {
    lineAnnotations.clear();
    lastScrollIndex = -1;

    vBoxRows.getChildren().clear();
    vBoxRows.getChildren().addAll(items);

    int pos = 0;

    for (final Label label : items)
    {
      final int finalPos = pos;

      unhighlightLabel(label);

      if (isHighlighting)
      {
        label.setOnMouseEntered(new EventHandler<MouseEvent>()
        {
          @Override
          public void handle(MouseEvent arg0)
          {
            if (!keyboardMode)
            {
              unhighlightPrevious();

              label.setStyle(STYLE_HIGHLIGHTED);
              lineListener.lineHighlighted(finalPos, lineType);
            }
          }
        });

        label.setOnMouseExited(new EventHandler<MouseEvent>()
        {
          @Override
          public void handle(MouseEvent arg0)
          {
            if (!keyboardMode)
            {
              unhighlightLabel(label);
            }
          }
        });

        label.setOnMouseMoved(new EventHandler<MouseEvent>()
        {
          @Override
          public void handle(MouseEvent arg0)
          {
            keyboardMode = false;
          }
        });
      }

      label.minWidthProperty().bind(scrollPane.widthProperty());
      pos++;
    }
  }

  private int checkBounds(int scrollIndex)
  {
    int min = 0;
    int max = vBoxRows.getChildren().size() - 1;

    return Math.min(Math.max(scrollIndex, min), max);
  }

  private void handleKeyUp()
  {
    scrollIndex--;

    scrollIndex = checkBounds(scrollIndex);

    lineListener.lineHighlighted(scrollIndex, lineType);
    highlightLine(scrollIndex);
  }

  private void handleKeyDown()
  {
    scrollIndex++;

    scrollIndex = checkBounds(scrollIndex);

    lineListener.lineHighlighted(scrollIndex, lineType);
    highlightLine(scrollIndex);
  }

  private void handleKeyLeft()
  {
    lineListener.handleFocusPrev();
  }

  private void handleKeyRight()
  {
    lineListener.handleFocusNext();
  }

  private void handleKeyPageUp()
  {
    scrollIndex -= linesPerPane();

    scrollIndex = checkBounds(scrollIndex);

    lineListener.lineHighlighted(scrollIndex, lineType);
    highlightLine(scrollIndex);
  }

  private void handleKeyPageDown()
  {
    scrollIndex += linesPerPane();

    scrollIndex = checkBounds(scrollIndex);

    lineListener.lineHighlighted(scrollIndex, lineType);
    highlightLine(scrollIndex);
  }

  private int linesPerPane()
  {
    return (int) (scrollPane.getHeight() / 10);
  }

  private void setUpContextMenu()
  {
    final ContextMenu contextMenu = new ContextMenu();

    MenuItem menuItemCopyToClipboard = new MenuItem("Copy to Clipboard");

    contextMenu.getItems().add(menuItemCopyToClipboard);

    vBoxRows.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>()
    {
      @Override
      public void handle(MouseEvent e)
      {
        if (e.getButton() == MouseButton.SECONDARY)
        {
          contextMenu.show(vBoxRows, e.getScreenX(), e.getScreenY());
        }
      }
    });

    menuItemCopyToClipboard.setOnAction(new EventHandler<ActionEvent>()
    {
      @Override
      public void handle(ActionEvent e)
      {
        final Clipboard clipboard = Clipboard.getSystemClipboard();
        final ClipboardContent content = new ClipboardContent();

        ObservableList<Node> items = vBoxRows.getChildren();

        content.putString(transformNodeItemsToTextUsing(items));

        clipboard.setContent(content);
      }
    });
  }

  private String transformNodeItemsToTextUsing(ObservableList<Node> items)
  {
    StringBuilder builder = new StringBuilder();

    for (Node item : items)
    {
      String line = ((Label) item).getText();

      builder.append(line).append(S_NEWLINE);
    }

    return builder.toString();
  }

  public void jumpTo(IMetaMember member)
  {
    scrollIndex = -1;

    int regexPos = findPosForRegex(member.getSignatureRegEx());

    if (regexPos == -1)
    {
      List<String> lines = Arrays.asList(originalSource.split(S_NEWLINE));

      scrollIndex = ParseUtil.findBestLineMatchForMemberSignature(member, lines);
    }
    else
    {
      scrollIndex = regexPos;
    }
  }

  public void clearAllHighlighting()
  {
    for (Node item : vBoxRows.getChildren())
    {
      unhighlightLabel(item);
    }
  }

  private void unhighlightLabel(Node node)
  {
    if (node instanceof BytecodeLabel)
    {
      node.setStyle(((BytecodeLabel) node).getUnhighlightedStyle());
    }
    else
    {
      node.setStyle(STYLE_UNHIGHLIGHTED);
    }
  }

  public void unhighlightPrevious()
  {
    if (lastScrollIndex >= 0 && lastScrollIndex < vBoxRows.getChildren().size())
    {
      Label label = (Label) vBoxRows.getChildren().get(lastScrollIndex);

      unhighlightLabel(label);
    }
  }

  public void highlightLine(int index)
  {
    unhighlightPrevious();

    if (index >= vBoxRows.getChildren().size())
    {
      index = vBoxRows.getChildren().size() - 1;
    }

    if (index >= 0)
    {
      // leave source position unchanged if not a known source line
      Label label = (Label) vBoxRows.getChildren().get(index);
      label.setStyle(STYLE_HIGHLIGHTED);

      lastScrollIndex = index;

      scrollIndex = index;

      setScrollBar();
    }
  }

  public Label getLabelAtIndex(int index)
  {
    ObservableList<Node> items = vBoxRows.getChildren();

    Label result = null;

    if (index >= 0 && index < items.size())
    {
      result = (Label) items.get(index);
    }

    if (result == null)
    {
      logger.warn("No label at index {}", index);
    }

    return result;
  }

  private int findPosForRegex(String regex)
  {
    int result = -1;

    ObservableList<Node> items = vBoxRows.getChildren();

    Pattern pattern = Pattern.compile(regex);

    int index = 0;

    for (Node item : items)
    {
      String line = ((Label) item).getText();

      Matcher matcher = pattern.matcher(line);
      if (matcher.find())
      {
        result = index;
        break;
      }

      index++;
    }

    return result;
  }

  public void setScrollBar()
  {
    if (vBoxRows.getChildren().size() > 0)
    {
      double scrollMin = scrollPane.getVmin();
      double scrollMax = scrollPane.getVmax();

      double count = vBoxRows.getChildren().size() - 1;

      double scrollPercent = 0;

      if (count > 0)
      {
        scrollPercent = (double) scrollIndex / count;
      }

      double scrollPos = scrollPercent * (scrollMax - scrollMin);

      scrollPane.setVvalue(scrollPos);
    }
  }
}
TOP

Related Classes of org.adoptopenjdk.jitwatch.ui.triview.Viewer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.