/** * Copyright 2011 multibit.org * * Licensed under the MIT license (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://opensource.org/licenses/mit-license.php * * 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.multibit.viewsystem.swing.view.ticker; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import org.multibit.controller.Controller; import org.multibit.controller.exchange.ExchangeController; import org.multibit.viewsystem.View; import org.multibit.viewsystem.swing.ColorAndFontConstants; import org.multibit.viewsystem.swing.MultiBitFrame; import org.multibit.viewsystem.swing.view.panels.HelpContentsPanel; import org.multibit.viewsystem.swing.view.components.FontSizer; import org.multibit.viewsystem.swing.view.components.MultiBitLabel; /** * A panel with a table showing the exchange rate data. * * @author jim * */ public class TickerTablePanel extends JPanel { private static final long serialVersionUID = 1235108820207842662L; private final Controller controller; private final ExchangeController exchangeController; private MultiBitFrame mainFrame; private JTable table; private TickerTableModel tickerTableModel; private JScrollPane scrollPane; private static final int HORIZONTAL_DELTA = 30; private static final int SCROLLBAR_WIDTH = 20; private static final int PER_COLUMN_HORIZONTAL_DELTA = 8; private static final int WINDOWS_TABLE_HEADER_HEIGHT_TWEAK = 4; private int moduloRow = 0; FontMetrics fontMetrics; Font font; private int idealHeight; public TickerTablePanel(MultiBitFrame mainFrame, ExchangeController exchangeController) { this.exchangeController = exchangeController; this.controller = this.exchangeController; this.mainFrame = mainFrame; font = FontSizer.INSTANCE.getAdjustedDefaultFontWithDelta(-1); fontMetrics = getFontMetrics(font); // Switch the dark and light row highlighting for Windows. if (System.getProperty("os.name", "unknown").startsWith("Win")) { moduloRow = 1; } else { moduloRow = 0; } initUI(); applyComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale())); } private void initUI() { createTicker(); } private void createTicker() { setBackground(ColorAndFontConstants.BACKGROUND_COLOR); setLayout(new GridBagLayout()); setOpaque(false); setFocusable(false); setToolTipText(HelpContentsPanel.createMultilineTooltipText(new String[] { controller.getLocaliser().getString("tickerTablePanel.tooltip"), "\n ", controller.getLocaliser().getString("tickerTablePanel.tooltip.clickToConfigure") })); // on mouse click - view the exchanges tab MouseListener viewPreferencesMouseListener = new MouseAdapter() { @Override public void mouseReleased(MouseEvent arg0) { controller.displayView(View.PREFERENCES_VIEW); } }; String tickerTooltipText = HelpContentsPanel.createMultilineTooltipText(new String[] { controller.getLocaliser().getString("tickerTablePanel.tooltip"), "\n ", controller.getLocaliser().getString("tickerTablePanel.tooltip.clickToConfigure") }); addMouseListener(viewPreferencesMouseListener); GridBagConstraints constraints = new GridBagConstraints(); tickerTableModel = new TickerTableModel(this.exchangeController); table = new JTable(tickerTableModel); table.setOpaque(true); table.setShowGrid(true); table.setGridColor(Color.lightGray); table.setBackground(ColorAndFontConstants.BACKGROUND_COLOR); table.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, SystemColor.windowBorder)); table.setComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale())); table.setRowHeight(getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()); table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); table.setRowSelectionAllowed(false); table.setColumnSelectionAllowed(false); table.getTableHeader().setReorderingAllowed(false); table.setToolTipText(tickerTooltipText); table.addMouseListener(viewPreferencesMouseListener); table.getTableHeader().addMouseListener(viewPreferencesMouseListener); table.getTableHeader().setToolTipText(tickerTooltipText); table.getTableHeader().setFont(FontSizer.INSTANCE.getAdjustedDefaultFontWithDelta(-1)); int tableHeaderHeight = fontMetrics.getHeight() + table.getTableHeader().getInsets().top + table.getTableHeader().getInsets().bottom; // Windows 8 has slightly taller headers so add a tweak for that. if (System.getProperty("os.name", "unknown").startsWith("Win")) { tableHeaderHeight = tableHeaderHeight + WINDOWS_TABLE_HEADER_HEIGHT_TWEAK; } int tickerWidth = setupColumnWidths(); setupTableHeaders(); idealHeight = (fontMetrics.getHeight() + table.getRowMargin()) * tickerTableModel.getRowCount() + tableHeaderHeight + tickerTableModel.getRowCount() + 10; setPreferredSize(new Dimension(tickerWidth, idealHeight)); scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale())); scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setViewportBorder(BorderFactory.createEmptyBorder()); scrollPane.addMouseListener(viewPreferencesMouseListener); setupScrollPane(tickerWidth); constraints.fill = GridBagConstraints.HORIZONTAL; constraints.gridx = 0; constraints.gridy = 0; constraints.gridwidth = 1; constraints.weightx = 1; constraints.weighty = 1; constraints.anchor = GridBagConstraints.CENTER; add(scrollPane, constraints); } private int setupColumnWidths() { // Column widths. String[] columnVariables = tickerTableModel.getColumnVariables(); int tickerWidth = HORIZONTAL_DELTA; if (tickerTableModel.getRowCount() > 1) { // There may be a scroll bar so give it some space. tickerWidth += SCROLLBAR_WIDTH; } int numberOfColumns = Math.min(table.getColumnCount(), columnVariables.length); for (int i = 0; i < numberOfColumns; i++) { // work out width int columnWidth; if (TickerTableModel.TICKER_COLUMN_CURRENCY.equals(columnVariables[i])) { columnWidth = PER_COLUMN_HORIZONTAL_DELTA + Math.max(Math.max( fontMetrics.stringWidth(controller.getLocaliser().getString("tickerTableModel." + columnVariables[i])), fontMetrics.stringWidth((String)tickerTableModel.getValueAt(0, i))), fontMetrics.stringWidth((String)tickerTableModel.getValueAt(1, i))); } else if (TickerTableModel.TICKER_COLUMN_EXCHANGE.equals(columnVariables[i])) { columnWidth = PER_COLUMN_HORIZONTAL_DELTA + Math.max(Math.max( fontMetrics.stringWidth(controller.getLocaliser().getString("tickerTableModel." + columnVariables[i])), fontMetrics.stringWidth((String)tickerTableModel.getValueAt(0, i))), fontMetrics.stringWidth((String)tickerTableModel.getValueAt(1, i))); } else { columnWidth = PER_COLUMN_HORIZONTAL_DELTA + Math.max( fontMetrics.stringWidth(controller.getLocaliser().getString("tickerTableModel." + columnVariables[i])), fontMetrics.stringWidth("000000.00000")); } tickerWidth += columnWidth; table.getColumnModel().getColumn(i).setPreferredWidth(columnWidth); } return tickerWidth; } private void setupTableHeaders() { // Column justification. String[] columnVariables = tickerTableModel.getColumnVariables(); int numberOfColumns = Math.min(table.getColumnCount(), columnVariables.length); for (int i = 0; i < numberOfColumns; i++) { TableCellRenderer columnRenderer; if (i == numberOfColumns - 1) { columnRenderer = new CurrencyCenterJustifiedWithRightBorderRenderer(); } else { columnRenderer = new CurrencyCenterJustifiedRenderer(); } table.getColumnModel().getColumn(i).setCellRenderer(columnRenderer); } TableCellRenderer renderer = table.getTableHeader().getDefaultRenderer(); JLabel label = (JLabel) renderer; label.setHorizontalAlignment(JLabel.CENTER); } private void setupScrollPane(int tickerWidth) { scrollPane.getViewport().setPreferredSize( new Dimension(tickerWidth, idealHeight)); scrollPane.setMinimumSize(new Dimension(tickerWidth, idealHeight)); scrollPane.setOpaque(false); scrollPane.setBackground(ColorAndFontConstants.BACKGROUND_COLOR); scrollPane.getViewport().setOpaque(false); scrollPane.getViewport().setBackground(ColorAndFontConstants.BACKGROUND_COLOR); } public void update() { int tickerWidth = setupColumnWidths(); setupTableHeaders(); setupScrollPane(tickerWidth); table.invalidate(); table.validate(); table.repaint(); invalidate(); validate(); repaint(); mainFrame.getHeaderPanel().invalidate(); mainFrame.getHeaderPanel().validate(); mainFrame.getHeaderPanel().repaint(); } class CurrencyCenterJustifiedRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1549545L; MultiBitLabel label = new MultiBitLabel(""); @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { label.setHorizontalAlignment(SwingConstants.CENTER); label.setBackground(ColorAndFontConstants.BACKGROUND_COLOR); label.setOpaque(true); label.setText((String) value); label.setFont(font); Color backgroundColor = (row % 2 == moduloRow ? ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR : ColorAndFontConstants.BACKGROUND_COLOR); label.setBackground(backgroundColor); label.setForeground(table.getForeground()); return label; } } class CurrencyCenterJustifiedWithRightBorderRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 9949545L; MultiBitLabel label = new MultiBitLabel(""); @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { label.setHorizontalAlignment(SwingConstants.CENTER); label.setBackground(ColorAndFontConstants.BACKGROUND_COLOR); label.setOpaque(true); label.setText((String) value); label.setFont(font); Color backgroundColor = (row % 2 == moduloRow ? ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR : ColorAndFontConstants.BACKGROUND_COLOR); label.setBackground(backgroundColor); label.setForeground(table.getForeground()); return label; } } public int getIdealHeight() { return idealHeight; } }