/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pdfbox.debugger.hexviewer; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import javax.swing.JComponent; /** * @author Khyrul Bashar * * This class shows corresponding ASCII characters for bytes. For every 16 byte there is one line. * This paints the only visible contents at one time. */ class ASCIIPane extends JComponent implements HexModelChangeListener { private final HexModel model; private int selectedLine = -1; private int selectedIndexInLine; /** * Constructor. * @param model HexModel instance. */ ASCIIPane(HexModel model) { this.model = model; setPreferredSize(new Dimension(HexView.ASCII_PANE_WIDTH, HexView.CHAR_HEIGHT * (model.totalLine()+1))); model.addHexModelChangeListener(this); setFont(HexView.FONT); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHints(HexView.RENDERING_HINTS); Rectangle bound = getVisibleRect(); int x = HexView.LINE_INSET; int y = bound.y; if (y == 0 || y%HexView.CHAR_HEIGHT != 0) { y += HexView.CHAR_HEIGHT - y%HexView.CHAR_HEIGHT; } int firstLine = y/HexView.CHAR_HEIGHT; for (int line = firstLine; line < firstLine + bound.getHeight()/HexView.CHAR_HEIGHT; line++) { if (line > model.totalLine()) { break; } if (line == selectedLine) { paintInSelected(g, x, y); } else { char[] chars = model.getLineChars(line); g.drawChars(chars, 0, chars.length, x, y); } x = HexView.LINE_INSET; y += HexView.CHAR_HEIGHT; } } /** * Paint a selected line * @param g Graphics instance. * @param x int. x axis value. * @param y int. y axis value. */ private void paintInSelected(Graphics g, int x, int y) { g.setFont(HexView.BOLD_FONT); char[] content = model.getLineChars(selectedLine); g.drawChars(content, 0, selectedIndexInLine - 0, x, y); g.setColor(HexView.SELECTED_COLOR); x += g.getFontMetrics().charsWidth(content, 0, selectedIndexInLine-0); g.drawChars(content, selectedIndexInLine, 1, x, y); g.setColor(Color.black); x += g.getFontMetrics().charWidth(content[selectedIndexInLine]); g.drawChars(content, selectedIndexInLine+1, (content.length-1)-selectedIndexInLine, x, y); g.setFont(HexView.FONT); } @Override public void hexModelChanged(HexModelChangedEvent event) { repaint(); } /** * Updates the line text for a given index. It is used when a byte is * selected in hex pane. * @param index int. */ void setSelected(int index) { selectedLine = HexModel.lineNumber(index); selectedIndexInLine = HexModel.elementIndexInLine(index); repaint(); } }