diff --git a/ethereumj-studio/src/main/java/org/ethereum/gui/BlockChainTable.java b/ethereumj-studio/src/main/java/org/ethereum/gui/BlockChainTable.java index 14533e7e..3a8d4922 100644 --- a/ethereumj-studio/src/main/java/org/ethereum/gui/BlockChainTable.java +++ b/ethereumj-studio/src/main/java/org/ethereum/gui/BlockChainTable.java @@ -1,40 +1,110 @@ package org.ethereum.gui; import org.ethereum.core.Block; +import org.ethereum.core.Transaction; +import org.ethereum.manager.WorldManager; +import org.ethereum.util.ByteUtil; +import org.ethereum.util.Utils; import javax.swing.*; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.TableCellRenderer; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.*; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.*; +import java.util.ArrayList; /** * www.ethereumJ.com - * @author: Roman Mandeleil - * Created on: 15/05/14 12:36 + * + * @author: Adrian Benko + * Created on: 27/08/14 18:22 */ -public class BlockChainTable extends JFrame { +public class BlockChainTable extends JFrame implements ActionListener { + + final static int BLOCK_CHECK_INTERVAL = 1000; + final static String FONT_NAME = "Courier New"; + final static int FONT_SIZE_TITLE = 20; + final static int FONT_SIZE = 13; + + final static Font boldTitle = new Font(FONT_NAME, Font.BOLD, FONT_SIZE_TITLE); + final static Font bold = new Font(FONT_NAME, Font.BOLD, FONT_SIZE); + final static Font plain = new Font(FONT_NAME, Font.PLAIN, FONT_SIZE); + final static Color HILIT_COLOR = Color.LIGHT_GRAY; + + class MyDocumentFilter extends DocumentFilter { + @Override + public void insertString(FilterBypass fb, int off + , String str, AttributeSet attr) + throws BadLocationException { + // remove non-digits + fb.insertString(off, str.replaceAll("\\D++", ""), attr); + } + + @Override + public void replace(FilterBypass fb, int off + , int len, String str, AttributeSet attr) + throws BadLocationException { + // remove non-digits + fb.replace(off, len, str.replaceAll("\\D++", ""), attr); + } + } + + private volatile boolean running; + private TransactionData transactionDataWindow = null; private JPanel topPanel; - private JTable table; - private JScrollPane scrollPane; + private JPanel titlePanel; + private JPanel blockPanel; + private JPanel transactionsPanel; + private JScrollPane scrollPane; - private int lastFindIndex = 0; + JTextField blockNumberText; + JButton firstBlock; + JButton prevBlock; + JButton nextBlock; + JButton lastBlock; + JLabel blocksCount; + JTextField findText; + JButton findPrev; + JButton findNext; + + JTextField blockN; + JTextField minGasPrice; + JTextField gasLimit; + JTextField gasUsed; + JTextField timestamp; + JTextField difficulty; + JTextField hash; + JTextField parentHash; + JTextField uncleHash; + JTextField stateRoot; + JTextField trieRoot; + JTextField coinbase; + JTextField nonce; + JTextField extraData; + + Thread t; + + private int lastFindIndex = -1; + private String textToFind = ""; + private java.util.List foundBlocks; + final Highlighter.HighlightPainter painter; ToolBar toolBar; public BlockChainTable(ToolBar toolBar) { - this.toolBar = toolBar; addCloseAction(); - final BlockChainTable blockchainTable = this; + foundBlocks = new ArrayList(); + painter = new DefaultHighlighter.DefaultHighlightPainter(HILIT_COLOR); setTitle("Block Chain Table"); - setSize(700, 400); - setLocation(315, 180); + setSize(900, 400); + setLocation(315, 270); setBackground(Color.gray); java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png"); @@ -42,100 +112,738 @@ public class BlockChainTable extends JFrame { Image img = kit.createImage(url); this.setIconImage(img); + // Create a panel to hold all other components topPanel = new JPanel(); - topPanel.setLayout(new BorderLayout()); - getContentPane().add(topPanel); + topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.PAGE_AXIS)); + getContentPane().add(topPanel, BorderLayout.LINE_START); - // Create a new table getInstance() - table = new JTable(); - table.setModel(new BlockTableModel()); + titlePanel = new JPanel(new FlowLayout()); + titlePanel.setMaximumSize(new Dimension(Short.MAX_VALUE, 50)); + createTitlePanel(this); - table.setFont(new Font("Courier New", Font.PLAIN, 13)); - table.setForeground(Color.GRAY); - table.setTableHeader(null); + blockPanel = new JPanel(new GridBagLayout()); + blockPanel.setMaximumSize(new Dimension(Short.MAX_VALUE, 160)); + createBlockPanel(); - TableCellRenderer tcr = table.getDefaultRenderer(String.class); - DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) tcr; - renderer.setHorizontalAlignment(SwingConstants.LEFT); - renderer.setVerticalAlignment(SwingConstants.TOP); + transactionsPanel = new JPanel(new GridBagLayout()); + transactionsPanel.setMaximumSize(new Dimension(Short.MAX_VALUE, 160)); + fillBlock(this); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - table.setCellSelectionEnabled(true); + titlePanel.setAlignmentX(0); + topPanel.add(titlePanel); + blockPanel.setAlignmentX(0); + topPanel.add(blockPanel); - table.setRowMargin(3); - table.setRowHeight(420); + JLabel transactionsLabel = new JLabel("Transactions "); + transactionsLabel.setFont(bold); + transactionsLabel.setAlignmentX(0); + transactionsLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + topPanel.add(transactionsLabel); - table.getColumnModel().getColumn(0).setCellRenderer(new TableCellLongTextRenderer()); + scrollPane = new JScrollPane(transactionsPanel); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + scrollPane.setAlignmentX(0); + topPanel.add(scrollPane); - table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), "Copy"); - table.getActionMap().put("Copy", new AbstractAction() { + topPanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), "Copy"); + topPanel.getActionMap().put("Copy", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - if (UIEthereumManager.ethereum.getBlockChain().getSize() - 1 < lastFindIndex) return; + if (WorldManager.getInstance().getBlockchain().getSize() - 1 < lastFindIndex) return; - Block block = UIEthereumManager.ethereum.getBlockChain().getBlockByNumber(lastFindIndex); - StringSelection stsel = new StringSelection(block.toString()); + Block block = WorldManager.getInstance().getBlockchain().getBlockByNumber(lastFindIndex); + StringSelection selection = new StringSelection(block.toString()); Clipboard system = Toolkit.getDefaultToolkit().getSystemClipboard(); - system.setContents(stsel,stsel); + system.setContents(selection, selection); } }); - table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F, KeyEvent.CTRL_DOWN_MASK), "Find"); - table.getActionMap().put("Find", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - - String toFind = JOptionPane.showInputDialog(blockchainTable, "Find:", - "Find in BlockChain", JOptionPane.QUESTION_MESSAGE); - - if (toFind.equals("")) { - lastFindIndex = 0; - return; - } - - for (int i = lastFindIndex + 1; i < UIEthereumManager.ethereum.getBlockChain().getSize(); ++i) { - - if (UIEthereumManager.ethereum.getBlockChain().getSize() - 1 < i) return; - Block block = UIEthereumManager.ethereum.getBlockChain().getBlockByNumber(i); - boolean found = block.toString().toLowerCase().contains(toFind.toLowerCase()); - if (found) { - // TODO: now we find the first occur - // TODO: in the future I should keep - // TODO: all of them and allow to jump over them - table.scrollRectToVisible(table.getCellRect(i, 0, true)); - lastFindIndex = i; - break; + t = new Thread() { + public void run() { + running = true; + while (running) { + blocksCount.setText("" + WorldManager.getInstance().getBlockchain().getSize()); + try { + sleep(BLOCK_CHECK_INTERVAL); + } catch (InterruptedException e) { } } } - }); - - table.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - lastFindIndex = ((JTable) (e.getSource())).rowAtPoint(e.getPoint()); - super.mouseClicked(e); - } - }); - // Add the table to a scrolling pane - scrollPane = new JScrollPane(table); - topPanel.add(scrollPane, BorderLayout.CENTER); + }; + t.start(); } - public void addCloseAction() { - this.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - toolBar.chainToggle.setSelected(false); + public void actionPerformed(ActionEvent e) { + long blockNum = Long.parseLong(blockNumberText.getText()); + if ("firstBlock".equals(e.getActionCommand())) { + blockNum = 0; + } else if ("prevBlock".equals(e.getActionCommand())) { + if (blockNum > 0) { + blockNum--; + } + } else if ("nextBlock".equals(e.getActionCommand())) { + if (blockNum < WorldManager.getInstance().getBlockchain().getSize() - 1) { + blockNum++; + } + } else if ("lastBlock".equals(e.getActionCommand())) { + blockNum = WorldManager.getInstance().getBlockchain().getSize() - 1; + } else if ("findPrev".equals(e.getActionCommand())) { + if (findText.getText().length() > 0) { + if (textToFind.equals(findText.getText())) { + if (lastFindIndex > 0) { + blockNum = foundBlocks.get(lastFindIndex - 1); + lastFindIndex--; + } else { + blockNum = findBlock(textToFind, blockNum, false); + } + } else { + textToFind = findText.getText(); + lastFindIndex = -1; + foundBlocks.clear(); + blockNum = findBlock(textToFind, blockNum, false); + } + } + } else if ("findNext".equals(e.getActionCommand())) { + if (findText.getText().length() > 0) { + if (textToFind.equals(findText.getText())) { + if (lastFindIndex > -1 && foundBlocks.size() > lastFindIndex + 1) { + blockNum = foundBlocks.get(lastFindIndex + 1); + lastFindIndex++; + } else { + blockNum = findBlock(textToFind, blockNum, true); + } + } else { + textToFind = findText.getText(); + lastFindIndex = -1; + foundBlocks.clear(); + blockNum = findBlock(textToFind, blockNum, true); + } + } + } + blockNumberText.setText("" + blockNum); + fillBlock(this); + } - } - }); - } + private long findBlock(String textToFind, long blockNum, boolean forward) { + if (forward) { + for (long i = blockNum + 1; i < WorldManager.getInstance().getBlockchain().getSize(); i++) { + Block block = WorldManager.getInstance().getBlockchain().getBlockByNumber(i); + if (block.toString().toLowerCase().contains(textToFind.toLowerCase())) { + foundBlocks.add(i); + lastFindIndex = foundBlocks.size() - 1; + break; + } + } + } else { + for (long i = blockNum - 1; i >= 0; i--) { + Block block = WorldManager.getInstance().getBlockchain().getBlockByNumber(i); + if (block.toString().toLowerCase().contains(textToFind.toLowerCase())) { + foundBlocks.add(0, i); + lastFindIndex = 0; + break; + } + } + } + return foundBlocks.get(lastFindIndex); + } + + public void terminate() { + running = false; + } + + public void addCloseAction() { + this.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + toolBar.chainToggle.setSelected(false); + if (transactionDataWindow != null) { + transactionDataWindow.setVisible(false); + } + } + }); + } + + public static void main(String args[]) { + BlockChainTable mainFrame = new BlockChainTable(null); + mainFrame.setVisible(true); + mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + + + private void createTitlePanel(final BlockChainTable blockchainTable) { + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + + JLabel blockNumberLabel = new JLabel("Block #"); + blockNumberLabel.setFont(boldTitle); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 10, 0, 0); + titlePanel.add(blockNumberLabel, c); + + blockNumberText = new JTextField("0", 7); + ((AbstractDocument) blockNumberText.getDocument()).setDocumentFilter( + new MyDocumentFilter()); + // Listen for changes in the text + blockNumberText.getDocument().addDocumentListener(new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + fillBlock(blockchainTable); + } + + public void removeUpdate(DocumentEvent e) { + fillBlock(blockchainTable); + } + + public void insertUpdate(DocumentEvent e) { + fillBlock(blockchainTable); + } + }); + + blockNumberText.setFont(boldTitle); + c.gridx = 1; + c.gridy = 0; + c.weightx = 1.0; + c.insets = new Insets(0, 0, 0, 10); + titlePanel.add(blockNumberText, c); + + firstBlock = new JButton("|<"); + firstBlock.setFont(plain); + firstBlock.setActionCommand("firstBlock"); + firstBlock.addActionListener(this); + c.gridx = 2; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 0, 0, 0); + titlePanel.add(firstBlock, c); + + prevBlock = new JButton("<"); + prevBlock.setFont(plain); + prevBlock.setActionCommand("prevBlock"); + prevBlock.addActionListener(this); + c.gridx = 3; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 0, 0, 0); + titlePanel.add(prevBlock, c); + + nextBlock = new JButton(">"); + nextBlock.setFont(plain); + nextBlock.setActionCommand("nextBlock"); + nextBlock.addActionListener(this); + c.gridx = 4; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 0, 0, 0); + titlePanel.add(nextBlock, c); + + lastBlock = new JButton(">|"); + lastBlock.setFont(plain); + lastBlock.setActionCommand("lastBlock"); + lastBlock.addActionListener(this); + c.gridx = 5; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 0, 0, 0); + titlePanel.add(lastBlock, c); + + JLabel blocksCountLabel = new JLabel("Total blocks: "); + blocksCountLabel.setFont(plain); + c.gridx = 6; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 10, 0, 0); + titlePanel.add(blocksCountLabel, c); + + blocksCount = new JLabel(); + blocksCount.setFont(plain); + c.gridx = 7; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 0, 0, 0); + titlePanel.add(blocksCount, c); + + JLabel findLabel = new JLabel("Find "); + findLabel.setFont(plain); + c.gridx = 8; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 10, 0, 0); + titlePanel.add(findLabel, c); + + findText = new JTextField(12); + findText.setFont(plain); + c.gridx = 9; + c.gridy = 0; + c.weightx = 3.0; + c.insets = new Insets(0, 0, 0, 0); + titlePanel.add(findText, c); + + findPrev = new JButton("<"); + findPrev.setFont(plain); + findPrev.setActionCommand("findPrev"); + findPrev.addActionListener(this); + c.gridx = 10; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 10, 0, 0); + titlePanel.add(findPrev, c); + + findNext = new JButton(">"); + findNext.setFont(plain); + findNext.setActionCommand("findNext"); + findNext.addActionListener(this); + c.gridx = 11; + c.gridy = 0; + c.weightx = 0.0; + c.insets = new Insets(0, 0, 0, 10); + titlePanel.add(findNext, c); + } + + private void createBlockPanel() { + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + + JLabel summaryLabel = new JLabel("Summary "); + summaryLabel.setFont(bold); + c.gridx = 0; + c.gridy = 1; + c.insets = new Insets(0, 10, 0, 0); + blockPanel.add(summaryLabel, c); + + JLabel blocknLabel = new JLabel("Block#"); + blocknLabel.setFont(plain); + c.weightx = 1.0; + c.gridx = 0; + c.gridy = 2; + blockPanel.add(blocknLabel, c); + + blockN = new JTextField(); + blockN.setEditable(false); + blockN.setBorder(null); + blockN.setFont(plain); + c.gridx = 1; + c.gridy = 2; + blockPanel.add(blockN, c); + + JLabel minGasPriceLabel = new JLabel("Min gas price"); + minGasPriceLabel.setFont(plain); + c.weightx = 1.0; + c.gridx = 0; + c.gridy = 3; + blockPanel.add(minGasPriceLabel, c); + + minGasPrice = new JTextField(); + minGasPrice.setEditable(false); + minGasPrice.setBorder(null); + minGasPrice.setFont(plain); + c.gridx = 1; + c.gridy = 3; + blockPanel.add(minGasPrice, c); + + JLabel gasLimitLabel = new JLabel("Gas limit"); + gasLimitLabel.setFont(plain); + c.gridx = 0; + c.gridy = 4; + blockPanel.add(gasLimitLabel, c); + + gasLimit = new JTextField(); + gasLimit.setEditable(false); + gasLimit.setBorder(null); + gasLimit.setFont(plain); + c.gridx = 1; + c.gridy = 4; + blockPanel.add(gasLimit, c); + + JLabel gasUsedLabel = new JLabel("Gas used"); + gasUsedLabel.setFont(plain); + c.gridx = 0; + c.gridy = 5; + blockPanel.add(gasUsedLabel, c); + + gasUsed = new JTextField(); + gasUsed.setEditable(false); + gasUsed.setBorder(null); + gasUsed.setFont(plain); + c.gridx = 1; + c.gridy = 5; + blockPanel.add(gasUsed, c); + + JLabel timestampLabel = new JLabel("Timestamp"); + timestampLabel.setFont(plain); + c.gridx = 0; + c.gridy = 6; + blockPanel.add(timestampLabel, c); + + timestamp = new JTextField(); + timestamp.setEditable(false); + timestamp.setBorder(null); + timestamp.setFont(plain); + c.gridx = 1; + c.gridy = 6; + blockPanel.add(timestamp, c); + + JLabel difficultyLabel = new JLabel("Difficulty"); + difficultyLabel.setFont(plain); + c.gridx = 0; + c.gridy = 7; + blockPanel.add(difficultyLabel, c); + + difficulty = new JTextField(); + difficulty.setEditable(false); + difficulty.setBorder(null); + difficulty.setFont(plain); + c.gridx = 1; + c.gridy = 7; + blockPanel.add(difficulty, c); + + JLabel extraDataLabel = new JLabel("Extra data"); + extraDataLabel.setFont(plain); + c.gridx = 0; + c.gridy = 9; + blockPanel.add(extraDataLabel, c); + + extraData = new JTextField(); + extraData.setEditable(false); + extraData.setBorder(null); + extraData.setFont(plain); + c.ipady = 1; + c.ipadx = 1; + c.gridx = 1; + c.gridy = 9; + c.gridwidth = GridBagConstraints.REMAINDER; + blockPanel.add(extraData, c); + + JLabel hashesLabel = new JLabel("Hashes "); + hashesLabel.setFont(bold); + c.gridx = 3; + c.gridy = 1; + c.gridwidth = 1; + blockPanel.add(hashesLabel, c); + + JLabel hashLabel = new JLabel("Hash"); + hashLabel.setFont(plain); + c.gridx = 3; + c.gridy = 2; + blockPanel.add(hashLabel, c); + + hash = new JTextField(); + hash.setEditable(false); + hash.setBorder(null); + hash.setFont(plain); + c.weightx = 3.0; + c.gridx = 4; + c.gridy = 2; + blockPanel.add(hash, c); + + JLabel parentHashLabel = new JLabel("Parent hash"); + parentHashLabel.setFont(plain); + c.weightx = 1.0; + c.gridx = 3; + c.gridy = 3; + blockPanel.add(parentHashLabel, c); + + parentHash = new JTextField(); + parentHash.setEditable(false); + parentHash.setBorder(null); + parentHash.setFont(plain); + c.gridx = 4; + c.gridy = 3; + blockPanel.add(parentHash, c); + + JLabel uncleHashLabel = new JLabel("Uncle hash"); + uncleHashLabel.setFont(plain); + c.gridx = 3; + c.gridy = 4; + blockPanel.add(uncleHashLabel, c); + + uncleHash = new JTextField(); + uncleHash.setEditable(false); + uncleHash.setBorder(null); + uncleHash.setFont(plain); + c.gridx = 4; + c.gridy = 4; + blockPanel.add(uncleHash, c); + + JLabel stateRootLabel = new JLabel("State root"); + stateRootLabel.setFont(plain); + c.weightx = 1.0; + c.gridx = 3; + c.gridy = 5; + blockPanel.add(stateRootLabel, c); + + stateRoot = new JTextField(); + stateRoot.setEditable(false); + stateRoot.setBorder(null); + stateRoot.setFont(plain); + c.gridx = 4; + c.gridy = 5; + blockPanel.add(stateRoot, c); + + JLabel trieRootLabel = new JLabel("Trie root"); + trieRootLabel.setFont(plain); + c.gridx = 3; + c.gridy = 6; + blockPanel.add(trieRootLabel, c); + + trieRoot = new JTextField(); + trieRoot.setEditable(false); + trieRoot.setBorder(null); + trieRoot.setFont(plain); + c.gridx = 4; + c.gridy = 6; + blockPanel.add(trieRoot, c); + + JLabel coinbaseLabel = new JLabel("Coinbase"); + coinbaseLabel.setFont(plain); + c.gridx = 3; + c.gridy = 7; + blockPanel.add(coinbaseLabel, c); + + coinbase = new JTextField(); + coinbase.setEditable(false); + coinbase.setBorder(null); + coinbase.setFont(plain); + c.gridx = 4; + c.gridy = 7; + blockPanel.add(coinbase, c); + + JLabel nonceLabel = new JLabel("Nonce"); + nonceLabel.setFont(plain); + c.gridx = 3; + c.gridy = 8; + blockPanel.add(nonceLabel, c); + + nonce = new JTextField(); + nonce.setEditable(false); + nonce.setBorder(null); + nonce.setFont(plain); + c.gridx = 4; + c.gridy = 8; + blockPanel.add(nonce, c); + } + + private void fillBlock(final BlockChainTable blockchainTable) { + if (blockNumberText.getText().length() == 0) return; + + long blockNum = Long.parseLong(blockNumberText.getText()); + if (blockNum > WorldManager.getInstance().getBlockchain().getSize() - 1) { + blockNum = WorldManager.getInstance().getBlockchain().getSize() - 1; + } + Block block = WorldManager.getInstance().getBlockchain().getBlockByNumber(blockNum); + blockN.setText("" + block.getNumber()); + highlightText(blockN); + minGasPrice.setText("" + block.getMinGasPrice()); + highlightText(minGasPrice); + gasLimit.setText("" + block.getGasLimit()); + highlightText(gasLimit); + gasUsed.setText("" + block.getGasUsed()); + highlightText(gasUsed); + timestamp.setText(Utils.longToDateTime(block.getTimestamp())); + highlightText(timestamp); + difficulty.setText(ByteUtil.toHexString(block.getDifficulty())); + highlightText(difficulty); + + hash.setText(ByteUtil.toHexString(block.getHash())); + highlightText(hash); + parentHash.setText(ByteUtil.toHexString(block.getParentHash())); + highlightText(parentHash); + uncleHash.setText(ByteUtil.toHexString(block.getUnclesHash())); + highlightText(uncleHash); + stateRoot.setText(ByteUtil.toHexString(block.getStateRoot())); + highlightText(stateRoot); + trieRoot.setText(ByteUtil.toHexString(block.getTxTrieRoot())); + highlightText(trieRoot); + coinbase.setText(ByteUtil.toHexString(block.getCoinbase())); + highlightText(coinbase); + nonce.setText(ByteUtil.toHexString(block.getNonce())); + highlightText(nonce); + if (block.getExtraData() != null) { + extraData.setText(ByteUtil.toHexString(block.getExtraData())); + highlightText(extraData); + } + + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + + transactionsPanel.removeAll(); + + int row = 1; + for (Transaction transaction : block.getTransactionsList()) { + JPanel transactionPanel = createTransactionPanel(blockchainTable, transaction); + + c.gridx = 0; + c.gridy = row; + c.weighty = 1; + c.weightx = 1; + c.anchor = GridBagConstraints.NORTHWEST; + c.insets = new Insets(10, 10, 0, 10); + transactionsPanel.add(transactionPanel, c); + row++; + } + transactionsPanel.repaint(); + } + + private JPanel createTransactionPanel(final BlockChainTable blockchainTable, final Transaction transaction) { + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + + JPanel transactionPanel = new JPanel(new GridBagLayout()); + transactionPanel.setBorder(BorderFactory.createLineBorder(Color.black)); + + JLabel senderLabel = new JLabel("Sender"); + senderLabel.setFont(plain); + c.gridx = 0; + c.gridy = 0; + c.insets = new Insets(10, 0, 0, 0); + transactionPanel.add(senderLabel, c); + + JTextField sender = new JTextField(ByteUtil.toHexString(transaction.getSender())); + highlightText(sender); + sender.setEditable(false); + sender.setBorder(null); + sender.setFont(plain); + c.gridx = 1; + c.gridy = 0; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(sender, c); + + JLabel gasPriceLabel = new JLabel("Gas price"); + gasPriceLabel.setFont(plain); + c.gridx = 2; + c.gridy = 0; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(gasPriceLabel, c); + + JTextField gasPrice = new JTextField(ByteUtil.toHexString(transaction.getGasPrice())); + highlightText(gasPrice); + gasPrice.setEditable(false); + gasPrice.setBorder(null); + gasPrice.setFont(plain); + c.gridx = 3; + c.gridy = 0; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(gasPrice, c); + + JLabel receiveAddressLabel = new JLabel("Receive address"); + receiveAddressLabel.setFont(plain); + c.gridx = 0; + c.gridy = 1; + c.insets = new Insets(0, 0, 0, 0); + transactionPanel.add(receiveAddressLabel, c); + + JTextField receiveAddress = new JTextField(ByteUtil.toHexString(transaction.getReceiveAddress())); + highlightText(receiveAddress); + receiveAddress.setEditable(false); + receiveAddress.setBorder(null); + receiveAddress.setFont(plain); + c.gridx = 1; + c.gridy = 1; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(receiveAddress, c); + + JLabel gasLimitLabel = new JLabel("Gas limit"); + gasLimitLabel.setFont(plain); + c.gridx = 2; + c.gridy = 1; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(gasLimitLabel, c); + + JTextField gasLimit = new JTextField(ByteUtil.toHexString(transaction.getGasLimit())); + highlightText(gasLimit); + gasLimit.setEditable(false); + gasLimit.setBorder(null); + gasLimit.setFont(plain); + c.gridx = 3; + c.gridy = 1; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(gasLimit, c); + + JLabel hashLabel = new JLabel("Hash"); + hashLabel.setFont(plain); + c.gridx = 0; + c.gridy = 2; + c.insets = new Insets(0, 0, 0, 0); + transactionPanel.add(hashLabel, c); + + JTextField hash = new JTextField(ByteUtil.toHexString(transaction.getHash())); + highlightText(hash); + hash.setEditable(false); + hash.setBorder(null); + hash.setFont(plain); + c.gridx = 1; + c.gridy = 2; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(hash, c); + + JLabel valueLabel = new JLabel("Value"); + valueLabel.setFont(plain); + c.gridx = 2; + c.gridy = 2; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(valueLabel, c); + + JTextField value = new JTextField(transaction.getValue() != null ? ByteUtil.toHexString(transaction.getValue()) : ""); + highlightText(value); + value.setEditable(false); + value.setBorder(null); + value.setFont(plain); + c.gridx = 3; + c.gridy = 2; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(value, c); + + JLabel nonceLabel = new JLabel("Nonce"); + nonceLabel.setFont(plain); + c.gridx = 0; + c.gridy = 3; + c.insets = new Insets(0, 0, 0, 0); + transactionPanel.add(nonceLabel, c); + + JTextField nonce = new JTextField(ByteUtil.toHexString(transaction.getNonce())); + highlightText(nonce); + nonce.setEditable(false); + nonce.setBorder(null); + nonce.setFont(plain); + c.gridx = 1; + c.gridy = 3; + c.insets = new Insets(0, 10, 0, 0); + transactionPanel.add(nonce, c); + + JButton data = new JButton("Data"); + data.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + if (transactionDataWindow == null) + transactionDataWindow = new TransactionData(blockchainTable); + transactionDataWindow.setData(transaction.getData()); + transactionDataWindow.setVisible(true); + transactionDataWindow.highlightText(findText.getText(), painter); + } + + }); + data.setFont(plain); + if (findText.getText().length() > 0 && ByteUtil.toHexString(transaction.getData()).contains(findText.getText())) { + data.setBackground(HILIT_COLOR); + } + c.gridx = 3; + c.gridy = 3; + c.insets = new Insets(0, 0, 10, 0); + transactionPanel.add(data, c); + + return transactionPanel; + } + + private void highlightText(JTextField textField) { + if (findText.getText().length() > 0 && textField.getText().contains(findText.getText())) { + try { + int end = textField.getText().indexOf(findText.getText()) + findText.getText().length(); + textField.getHighlighter().addHighlight(textField.getText().indexOf(findText.getText()), end, painter); + } catch (BadLocationException e) { + } + } + } - public static void main(String args[]) { - BlockChainTable mainFrame = new BlockChainTable(null); - mainFrame.setVisible(true); - mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } } diff --git a/ethereumj-studio/src/main/java/org/ethereum/gui/TableCellLongTextRenderer.java b/ethereumj-studio/src/main/java/org/ethereum/gui/TableCellLongTextRenderer.java deleted file mode 100644 index 56279051..00000000 --- a/ethereumj-studio/src/main/java/org/ethereum/gui/TableCellLongTextRenderer.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.ethereum.gui; - -import java.awt.*; - -import javax.swing.*; -import javax.swing.border.Border; -import javax.swing.border.EmptyBorder; -import javax.swing.table.TableCellRenderer; - -/** - * www.ethereumJ.com - * @author: Roman Mandeleil - * Created on: 15/05/14 13:08 - */ -public class TableCellLongTextRenderer extends JEditorPane implements TableCellRenderer{ - - protected static Border m_noFocusBorder; - - public TableCellLongTextRenderer() { - m_noFocusBorder = new EmptyBorder(1, 2, 1, 2); - setOpaque(true); - setBorder(m_noFocusBorder); - } - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - this.setText((String) value); - this.setSelectedTextColor(Color.BLUE); -// this.setWrapStyleWord(true); -// this.setLineWrap(true); - - setBackground(isSelected && !hasFocus ? table.getSelectionBackground() : table.getBackground()); - setForeground(isSelected && !hasFocus ? table.getSelectionForeground() : table.getForeground()); - setBorder(hasFocus? UIManager.getBorder("Table.focusCellHighlightBorder") : m_noFocusBorder); - - //set the JTextArea to the width of the table column - setSize(table.getColumnModel().getColumn(column).getWidth(), getPreferredSize().height); - if (table.getRowHeight(row) != getPreferredSize().height) { - //set the height of the table row to the calculated height of the JTextArea - table.setRowHeight(row, getPreferredSize().height); - } - - return this; - } - -} - diff --git a/ethereumj-studio/src/main/java/org/ethereum/gui/TransactionData.java b/ethereumj-studio/src/main/java/org/ethereum/gui/TransactionData.java new file mode 100644 index 00000000..0ca7b027 --- /dev/null +++ b/ethereumj-studio/src/main/java/org/ethereum/gui/TransactionData.java @@ -0,0 +1,64 @@ +package org.ethereum.gui; + +import org.ethereum.util.ByteUtil; + +import javax.swing.*; +import javax.swing.text.BadLocationException; +import javax.swing.text.Highlighter; +import java.awt.*; + +/** + * www.ethereumJ.com + * + * @author: Adrian Benko + * Created on: 27/08/14 18:22 + */ +public class TransactionData extends JFrame { + + private JPanel topPanel; + private JTextArea dataTextArea; + + public TransactionData(BlockChainTable blockChainTable) { + setTitle("Data"); + setSize(400, 400); + setLocation(350, 200); + setBackground(Color.gray); + + java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png"); + Toolkit kit = Toolkit.getDefaultToolkit(); + Image img = kit.createImage(url); + this.setIconImage(img); + + // Create a panel to hold all other components + topPanel = new JPanel(new BorderLayout()); + getContentPane().add(topPanel); + + dataTextArea = new JTextArea(); + dataTextArea.setEditable(false); + dataTextArea.setLineWrap(true); + dataTextArea.setOpaque(false); + dataTextArea.setWrapStyleWord(false); + dataTextArea.setFont(BlockChainTable.plain); + + JScrollPane scrollPane = new JScrollPane(dataTextArea); + topPanel.add(scrollPane, BorderLayout.CENTER); + } + + public void setData(byte[] data) { + dataTextArea.setText(ByteUtil.toHexString(data)); + topPanel.repaint(); + } + + public void highlightText(String findText, Highlighter.HighlightPainter painter) { + if (findText.length() > 0 && dataTextArea.getText().contains(findText)) { + int begin = dataTextArea.getText().indexOf(findText); + int end = begin + findText.length(); + try { + dataTextArea.getHighlighter().addHighlight(begin, end, painter); + } catch (BadLocationException e) { + } + dataTextArea.setCaretPosition(end); + } + } + +}