/**
* Copyright 2012 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.panels;
import com.google.bitcoin.core.Address;
import com.google.bitcoin.uri.BitcoinURI;
import com.google.bitcoin.uri.BitcoinURIParseException;
import org.joda.money.Money;
import org.multibit.controller.Controller;
import org.multibit.controller.bitcoin.BitcoinController;
import org.multibit.exchange.*;
import org.multibit.message.Message;
import org.multibit.message.MessageManager;
import org.multibit.model.bitcoin.BitcoinModel;
import org.multibit.model.bitcoin.WalletAddressBookData;
import org.multibit.model.bitcoin.WalletData;
import org.multibit.model.bitcoin.WalletInfoData;
import org.multibit.model.core.CoreModel;
import org.multibit.qrcode.QRCodeEncoderDecoder;
import org.multibit.qrcode.QRCodeGenerator;
import org.multibit.store.MultiBitWalletVersion;
import org.multibit.utils.ImageLoader;
import org.multibit.utils.WhitespaceTrimmer;
import org.multibit.viewsystem.DisplayHint;
import org.multibit.viewsystem.Viewable;
import org.multibit.viewsystem.dataproviders.BitcoinFormDataProvider;
import org.multibit.viewsystem.dataproviders.CopyQRCodeImageDataProvider;
import org.multibit.viewsystem.swing.ColorAndFontConstants;
import org.multibit.viewsystem.swing.MultiBitFrame;
import org.multibit.viewsystem.swing.action.CopyQRCodeImageAction;
import org.multibit.viewsystem.swing.action.MnemonicUtil;
import org.multibit.viewsystem.swing.action.PasteSwatchAction;
import org.multibit.viewsystem.swing.action.ZoomAction;
import org.multibit.viewsystem.swing.view.ImageSelection;
import org.multibit.viewsystem.swing.view.components.*;
import org.multibit.viewsystem.swing.view.models.AddressBookTableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.Collator;
import java.util.*;
import java.util.List;
/**
* Abstract parent class for SendBitcoinPanel and ReceiveBitcoinPanel
*
* @author jim
*
*/
public abstract class AbstractTradePanel extends JPanel implements Viewable, CopyQRCodeImageDataProvider, BitcoinFormDataProvider, CurrencyConverterListener {
public boolean isShowSidePanel() {
return showSidePanel;
}
public void setShowSidePanel(boolean showSidePanel) {
AbstractTradePanel.showSidePanel = showSidePanel;
}
private static final long serialVersionUID = 7227169670412230264L;
private static final Logger log = LoggerFactory.getLogger(AbstractTradePanel.class);
private static final int MINIMUM_QRCODE_PANEL_HORIZONTAL_SPACING = 30;
private static final int MINIMUM_QRCODE_PANEL_VERTICAL_SPACING = 80;
private static final int TABLE_BORDER = 3;
protected static final int PREFERRED_NUMBER_OF_LABEL_ROWS = 3;
protected MultiBitFrame mainFrame;
protected final Controller controller;
protected final BitcoinController bitcoinController;
protected MultiBitTextArea labelTextArea;
protected MultiBitTextField amountBTCTextField;
protected MultiBitTextField amountFiatTextField;
protected MultiBitLabel amountEqualsLabel;
protected MultiBitLabel amountUnitFiatLabel;
protected Money parsedAmountBTC = null;
protected Money parsedAmountFiat = null;
protected JLabel notificationLabel;
protected JPanel upperPanel;
protected AddressBookTableModel addressesTableModel;
protected JTable addressesTable;
protected MultiBitTextField addressTextField;
protected int selectedAddressRowModel;
protected SelectionListener addressesListener;
protected MultiBitButton createNewButton;
protected MultiBitButton deleteButton;
protected Action createNewAddressAction;
protected Action deleteAddressAction;
protected JLabel titleLabel;
protected MultiBitLabel qrCodeLabel;
protected JScrollPane qrCodeScrollPane;
public final static int QR_CODE_LEFT_COLUMN = 11;
protected static final int QRCODE_WIDTH = 140;
protected static final int QRCODE_HEIGHT = 140;
protected static final int TEXTFIELD_VERTICAL_DELTA = 16;
protected static final int HELP_BUTTON_INDENT = 6;
private static final int STENT_DELTA = 4;
protected FontMetrics fontMetrics;
protected int separatorSize;
protected int smallSeparatorSize;
protected MultiBitLabel displayUsingLabel;
protected MultiBitButton copyQRCodeImageButton;
protected MultiBitButton pasteSwatchButton;
protected MultiBitButton zoomButton;
protected JPanel qrCodeButtonPanelStent1;
protected JPanel qrCodeButtonPanelStent2;
protected JPanel qrCodeButtonPanelStent3;
protected JPanel qrCodeButtonPanelStent4;
protected JPanel forcer2;
protected MultiBitButton sidePanelButton;
protected static boolean showSidePanel = false;
private final AbstractTradePanel thisAbstractTradePanel;
private QRCodeGenerator qrCodeGenerator;
private JScrollPane addressesScrollPane;
/**
* map that maps one of the key constants in this class to the actual key to
* use for localisation
*
* this map is filled up in the constructors of the concrete impls
*/
protected Map<String, String> localisationKeyConstantToKeyMap;
protected String ADDRESSES_TITLE = "addressesTitle";
protected String CREATE_NEW_TOOLTIP = "createNewTooltip";
protected String DELETE_TOOLTIP = "deleteTooltip";
public AbstractTradePanel(MultiBitFrame mainFrame, BitcoinController bitcoinController) {
this.mainFrame = mainFrame;
this.bitcoinController = bitcoinController;
this.controller = this.bitcoinController;
this.thisAbstractTradePanel = this;
try {
setFont(FontSizer.INSTANCE.getAdjustedDefaultFontWithDelta(2 * ColorAndFontConstants.MULTIBIT_LARGE_FONT_INCREASE));
Font font = FontSizer.INSTANCE.getAdjustedDefaultFont();
fontMetrics = this.getFontMetrics(font);
separatorSize = (int) (fontMetrics.getHeight() * 0.5);
smallSeparatorSize = (int) (fontMetrics.getHeight() * 0.2);
localisationKeyConstantToKeyMap = new HashMap<String, String>();
populateLocalisationMap();
initUI();
labelTextArea.requestFocusInWindow();
displaySidePanel();
applyComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()));
CurrencyConverter.INSTANCE.addCurrencyConverterListener(this);
} catch (Exception e) {
log.error("Error in construction of AbstractTradePanel");
}
}
/**
* is it the receive bitcoin panel (return true) or the send bitcoin panel
* (return false)
*/
protected abstract boolean isReceiveBitcoin();
public abstract String getAddressConstant();
public abstract String getLabelConstant();
public abstract String getAmountConstant();
protected abstract Action getCreateNewAddressAction();
protected abstract Action getDeleteAddressAction();
/**
* method for concrete impls to populate the localisation map
*/
protected abstract void populateLocalisationMap();
public abstract void checkDeleteSendingEnabled();
/**
* get the layout stent for all the keys on the left hand side of the panel
*/
protected int calculateStentWidth() {
String[] keys = new String[] { "sendBitcoinPanel.addressLabel", "sendBitcoinPanel.labelLabel",
"sendBitcoinPanel.amountLabel", "receiveBitcoinPanel.addressLabel", "receiveBitcoinPanel.labelLabel",
"receiveBitcoinPanel.amountLabel" };
return MultiBitTitledPanel.calculateStentWidthForKeys(controller.getLocaliser(), keys, this) + STENT_DELTA;
}
/**
* get a localisation string - the key varies according to the concrete impl
*/
protected String getLocalisationString(String keyConstant, Object[] data) {
String stringToReturn = "";
// get the localisation key
if (localisationKeyConstantToKeyMap != null && keyConstant != null) {
String key = localisationKeyConstantToKeyMap.get(keyConstant);
stringToReturn = controller.getLocaliser().getString(key, data);
}
return stringToReturn;
}
protected void initUI() {
setMinimumSize(new Dimension(550, 220));
setLayout(new GridBagLayout());
setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
String showSidePanelText = controller.getModel().getUserPreference(BitcoinModel.SHOW_SIDE_PANEL);
if (!Boolean.FALSE.toString().equals(showSidePanelText)) {
showSidePanel = true;
}
GridBagConstraints constraints = new GridBagConstraints();
GridBagConstraints constraints2 = new GridBagConstraints();
upperPanel = new JPanel(new GridBagLayout());
upperPanel.setOpaque(false);
createFormPanel(upperPanel, constraints2);
createQRCodePanel(upperPanel, constraints2);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1.0;
constraints.weighty = 0.5;
constraints.anchor = GridBagConstraints.LINE_START;
add(upperPanel, constraints);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 0;
constraints.gridy = 1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1.0;
constraints.weighty = 2.0;
constraints.anchor = GridBagConstraints.LINE_START;
add(createAddressesPanel(), constraints);
CurrencyConverter.INSTANCE.updateFormatters();
updateFiatAmount();
}
protected void createFormPanelStentsAndForcers(JPanel panel, GridBagConstraints constraints) {
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = 1;
constraints.weighty = 0.01;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.LINE_START;
panel.add(MultiBitTitledPanel.createStent(calculateStentWidth(), separatorSize), constraints);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 1;
constraints.gridy = 2;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.CENTER;
panel.add(MultiBitTitledPanel.createStent(MultiBitTitledPanel.SEPARATION_BETWEEN_NAME_VALUE_PAIRS, separatorSize),
constraints);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 1;
constraints.gridy = 3;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.CENTER;
panel.add(
MultiBitTitledPanel.createStent(MultiBitTitledPanel.SEPARATION_BETWEEN_NAME_VALUE_PAIRS, fontMetrics.getHeight()
* PREFERRED_NUMBER_OF_LABEL_ROWS), constraints);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 1;
constraints.gridy = 4;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.CENTER;
panel.add(
MultiBitTitledPanel.createStent(MultiBitTitledPanel.SEPARATION_BETWEEN_NAME_VALUE_PAIRS, separatorSize),
constraints);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 2;
constraints.gridy = 2;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.CENTER;
panel.add(MultiBitTitledPanel.createStent(fontMetrics.stringWidth(MultiBitFrame.EXAMPLE_LONG_FIELD_TEXT), separatorSize),
constraints);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 1;
constraints.gridy = 4;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.CENTER;
panel.add(MultiBitTitledPanel.createStent(MultiBitTitledPanel.SEPARATION_BETWEEN_NAME_VALUE_PAIRS, separatorSize),
constraints);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 5;
constraints.gridy = 0;
constraints.weightx = 0.1;
constraints.weighty = 0.01;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.CENTER;
panel.add(MultiBitTitledPanel.createStent(separatorSize), constraints);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 7;
constraints.gridy = 0;
constraints.weightx = 0.1;
constraints.weighty = 0.01;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.CENTER;
panel.add(MultiBitTitledPanel.createStent(separatorSize), constraints);
constraints.fill = GridBagConstraints.VERTICAL;
constraints.gridx = 10;
constraints.gridy = 1;
constraints.weightx = 0.02;
constraints.weighty = 10000;
constraints.gridwidth = 1;
constraints.gridheight = 8;
constraints.anchor = GridBagConstraints.LINE_START;
JPanel dashedStent = MultiBitTitledPanel.createStent(smallSeparatorSize);
dashedStent.setBorder(new DashedBorder(controller.getLocaliser().getLocale()));
panel.add(dashedStent, constraints);
JPanel forcer1 = new JPanel();
forcer1.setOpaque(false);
//forcer1.setBorder(BorderFactory.createLineBorder(Color.BLUE));
forcer1.setMaximumSize(new Dimension(QRCODE_WIDTH, 1));
forcer1.setPreferredSize(new Dimension(QRCODE_WIDTH, 1));
forcer1.setMinimumSize(new Dimension((int) (QRCODE_WIDTH * 0.1), 1));
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 9;
constraints.gridy = 7;
constraints.weightx = 10000;
constraints.weighty = 4.0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.LINE_END;
panel.add(forcer1, constraints);
forcer2 = new JPanel();
forcer2.setOpaque(false);
forcer2.setMaximumSize(new Dimension((int) (QRCODE_WIDTH * 1.2), 1));
forcer2.setPreferredSize(new Dimension(QRCODE_WIDTH, 1));
forcer2.setMinimumSize(new Dimension((int) (QRCODE_WIDTH * 1.0), 1));
//forcer2.setBorder(BorderFactory.createLineBorder(Color.CYAN));
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = QR_CODE_LEFT_COLUMN;
constraints.gridy = 7;
constraints.weightx = 1;
constraints.weighty = 1.0;
constraints.gridwidth = 3;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.LINE_START;
panel.add(forcer2, constraints);
}
public void displaySidePanel() {
setQRCodePanelVisible(showSidePanel);
if (sidePanelButton == null) {
return;
}
MnemonicUtil mnemonicUtil = new MnemonicUtil(controller.getLocaliser());
if (showSidePanel) {
// show less
if (ComponentOrientation.LEFT_TO_RIGHT == ComponentOrientation.getOrientation(controller.getLocaliser().getLocale())) {
sidePanelButton.setIcon(ImageLoader.createImageIcon(ImageLoader.SIDE_PANEL_HIDE_ICON_FILE));
} else {
sidePanelButton.setIcon(ImageLoader.createImageIcon(ImageLoader.SIDE_PANEL_HIDE_RTL_ICON_FILE));
}
sidePanelButton.setText("");
sidePanelButton.setBorderPainted(false);
sidePanelButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinPanel.showLess.tooltip")));
sidePanelButton.setMnemonic(mnemonicUtil.getMnemonic(controller.getLocaliser().getString(
"sendBitcoinPanel.showLess.mnemonic")));
sidePanelButton.setVerticalTextPosition(JLabel.BOTTOM);
sidePanelButton.setHorizontalTextPosition(JLabel.LEFT);
} else {
// show more
if (ComponentOrientation.LEFT_TO_RIGHT == ComponentOrientation.getOrientation(controller.getLocaliser().getLocale())) {
sidePanelButton.setIcon(ImageLoader.createImageIcon(ImageLoader.SIDE_PANEL_SHOW_ICON_FILE));
} else {
sidePanelButton.setIcon(ImageLoader.createImageIcon(ImageLoader.SIDE_PANEL_SHOW_RTL_ICON_FILE));
}
sidePanelButton.setText("");
sidePanelButton.setBorderPainted(false);
sidePanelButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinPanel.showMore.tooltip")));
sidePanelButton.setMnemonic(mnemonicUtil.getMnemonic(controller.getLocaliser().getString(
"sendBitcoinPanel.showMore.mnemonic")));
sidePanelButton.setVerticalTextPosition(JLabel.BOTTOM);
sidePanelButton.setHorizontalTextPosition(JLabel.LEFT);
}
}
protected abstract JPanel createFormPanel(JPanel panel, GridBagConstraints constraints);
protected abstract void loadForm();
protected JPanel createAddressesHeaderPanel() {
JPanel addressesHeaderPanel = new JPanel();
addressesHeaderPanel.setOpaque(true);
addressesHeaderPanel.setBackground(ColorAndFontConstants.MID_BACKGROUND_COLOR);
addressesHeaderPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, SystemColor.windowBorder));
addressesHeaderPanel.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = 0.01;
constraints.weighty = 0.01;
constraints.anchor = GridBagConstraints.LINE_START;
addressesHeaderPanel.add(MultiBitTitledPanel.createStent(HELP_BUTTON_INDENT), constraints);
createNewAddressAction = getCreateNewAddressAction();
createNewButton = new MultiBitButton(createNewAddressAction, controller);
createNewButton.setText(controller.getLocaliser().getString("crudButton.new"));
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 1;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.weightx = 0.1;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.LINE_START;
addressesHeaderPanel.add(createNewButton, constraints);
int offset;
deleteAddressAction = getDeleteAddressAction();
if (isReceiveBitcoin()) {
// Put in a stent
MultiBitButton dummyDeleteButton = new MultiBitButton(deleteAddressAction, controller);
JPanel deleteButtonStent = MultiBitTitledPanel.createStent(dummyDeleteButton.getPreferredSize().width, dummyDeleteButton.getPreferredSize().height);
offset = 1;
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 2;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.weightx = 0.1;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.LINE_START;
addressesHeaderPanel.add(deleteButtonStent, constraints);
} else {
deleteButton = new MultiBitButton(deleteAddressAction, controller);
offset = 1;
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 2;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.weightx = 0.1;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.LINE_START;
addressesHeaderPanel.add(deleteButton, constraints);
}
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 2 + offset;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.CENTER;
addressesHeaderPanel.add(MultiBitTitledPanel.createStent(HELP_BUTTON_INDENT * 2), constraints);
titleLabel = new JLabel();
titleLabel.setHorizontalTextPosition(JLabel.CENTER);
titleLabel.setText(getLocalisationString(ADDRESSES_TITLE, null));
titleLabel.setFont(FontSizer.INSTANCE.getAdjustedDefaultFontWithDelta(ColorAndFontConstants.MULTIBIT_LARGE_FONT_INCREASE));
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 3 + offset;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.LINE_START;
addressesHeaderPanel.add(titleLabel, constraints);
JPanel filler2 = new JPanel();
filler2.setOpaque(false);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 4;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.weightx = 1000;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.LINE_START;
addressesHeaderPanel.add(filler2, constraints);
return addressesHeaderPanel;
}
protected JPanel createAddressesPanel() {
JPanel addressPanel = new JPanel();
addressPanel.setOpaque(true);
addressPanel.setBackground(ColorAndFontConstants.BACKGROUND_COLOR);
addressPanel.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
addressesTableModel = new AddressBookTableModel(this.bitcoinController, isReceiveBitcoin());
addressesTable = new JTable(addressesTableModel);
addressesTable.setOpaque(true);
addressesTable.setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
addressesTable.setShowGrid(false);
addressesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
addressesTable.setRowSelectionAllowed(true);
addressesTable.setColumnSelectionAllowed(false);
addressesTable.setRowHeight(getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight() + ShowTransactionsPanel.HEIGHT_DELTA);
// row sorter
TableRowSorter<TableModel> rowSorter = new TableRowSorter<TableModel>(addressesTable.getModel());
addressesTable.setRowSorter(rowSorter);
// sort by date descending
List<TableRowSorter.SortKey> sortKeys = new ArrayList<TableRowSorter.SortKey>();
sortKeys.add(new TableRowSorter.SortKey(0, SortOrder.ASCENDING));
rowSorter.setSortKeys(sortKeys);
Comparator<String> comparator = new Comparator<String>() {
Collator collator;
@Override
public int compare(String o1, String o2) {
if (collator == null) {
collator = Collator.getInstance(controller.getLocaliser().getLocale());
}
if (o1 == null) {
return 1;
} else if (o2 == null) {
return -1;
} else if ("".equals(o1) && !"".equals(o2)) {
return 1;
} else if ("".equals(o2) && !"".equals(o1)) {
return -1;
} else {
return collator.compare(o1, o2);
}
}
};
rowSorter.setComparator(0, comparator);
// justify column headers
TableCellRenderer renderer = addressesTable.getTableHeader().getDefaultRenderer();
JLabel label = (JLabel) renderer;
if (ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()).isLeftToRight()) {
label.setHorizontalAlignment(JLabel.LEFT);
} else {
label.setHorizontalAlignment(JLabel.RIGHT);
}
addressesTable.getTableHeader().setFont(FontSizer.INSTANCE.getAdjustedDefaultFont());
TableColumn tableColumn = addressesTable.getColumnModel().getColumn(0); // label
tableColumn.setPreferredWidth(40);
if (ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()).isLeftToRight()) {
tableColumn.setCellRenderer(new LeftJustifiedRenderer());
} else {
tableColumn.setCellRenderer(new RightJustifiedRenderer());
}
// description leading justified (set explicitly as it does not seem to
// work otherwise)
tableColumn = addressesTable.getColumnModel().getColumn(1); // address
tableColumn.setPreferredWidth(120);
// addresses leading justified (set explicitly as it does not seem to
// work otherwise)
if (ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()).isLeftToRight()) {
tableColumn.setCellRenderer(new LeftJustifiedRenderer());
} else {
tableColumn.setCellRenderer(new RightJustifiedRenderer());
}
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.weightx = 1;
constraints.weighty = 0.05;
constraints.anchor = GridBagConstraints.LINE_START;
addressPanel.add(createAddressesHeaderPanel(), constraints);
addressesScrollPane = new JScrollPane(addressesTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
setupScrollPane();
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 0;
constraints.gridy = 1;
constraints.gridwidth = 2;
constraints.weightx = 1;
constraints.weighty = 1;
addressPanel.add(addressesScrollPane, constraints);
// add on a selection listener
addressesListener = new SelectionListener();
addressesTable.getSelectionModel().addListSelectionListener(addressesListener);
return addressPanel;
}
private void setupScrollPane() {
addressesScrollPane.getViewport().setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
addressesScrollPane.setViewportBorder(BorderFactory.createEmptyBorder());
addressesScrollPane.getHorizontalScrollBar().setUnitIncrement(CoreModel.SCROLL_INCREMENT);
addressesScrollPane.getVerticalScrollBar().setUnitIncrement(CoreModel.SCROLL_INCREMENT);
}
protected void setQRCodePanelVisible(boolean visible) {
if (displayUsingLabel != null) {
displayUsingLabel.setVisible(visible);
}
if (qrCodeScrollPane != null) {
qrCodeScrollPane.setVisible(visible);
}
if (copyQRCodeImageButton != null) {
copyQRCodeImageButton.setVisible(visible);
}
if (pasteSwatchButton != null) {
pasteSwatchButton.setVisible(visible);
}
if (zoomButton != null) {
zoomButton.setVisible(visible);
}
if (qrCodeButtonPanelStent1 != null) {
qrCodeButtonPanelStent1.setVisible(visible);
}
if (qrCodeButtonPanelStent2 != null) {
qrCodeButtonPanelStent2.setVisible(visible);
}
if (qrCodeButtonPanelStent3 != null) {
qrCodeButtonPanelStent3.setVisible(visible);
}
if (qrCodeButtonPanelStent4 != null) {
qrCodeButtonPanelStent4.setVisible(visible);
}
if (forcer2 != null) {
forcer2.setVisible(visible);
}
if (qrCodeLabel != null) {
qrCodeLabel.invalidate();
qrCodeLabel.validate();
}
if (upperPanel != null) {
upperPanel.invalidate();
upperPanel.validate();
}
thisAbstractTradePanel.repaint();
}
class SelectionListener implements ListSelectionListener {
boolean enabled;
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
SelectionListener() {
enabled = true;
}
@Override
public void valueChanged(ListSelectionEvent event) {
if (enabled) {
int viewRow = addressesTable.getSelectedRow();
if (viewRow >= 0) {
selectedAddressRowModel = addressesTable.convertRowIndexToModel(viewRow);
WalletAddressBookData rowData = addressesTableModel.getAddressBookDataByRow(selectedAddressRowModel,
thisAbstractTradePanel.isReceiveBitcoin());
if (rowData != null) {
bitcoinController.getModel().setActiveWalletPreference(thisAbstractTradePanel.getAddressConstant(),
rowData.getAddress());
bitcoinController.getModel().setActiveWalletPreference(thisAbstractTradePanel.getLabelConstant(),
rowData.getLabel());
if (addressTextField != null) {
addressTextField.setText(rowData.getAddress());
}
labelTextArea.setText(rowData.getLabel());
String amountForQRCode = "";
if (parsedAmountBTC != null && parsedAmountBTC.getAmount() != null) {
amountForQRCode = controller.getLocaliser().bitcoinValueToStringNotLocalised(parsedAmountBTC.getAmount().toBigInteger(), false, false);
}
displayQRCode(rowData.getAddress(), amountForQRCode, labelTextArea.getText());
}
}
}
}
}
static class LeftJustifiedRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1549115L;
MultiBitLabel label = new MultiBitLabel("");
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
label.setHorizontalAlignment(SwingConstants.LEFT);
label.setOpaque(true);
label.setBorder(new EmptyBorder(new Insets(1, TABLE_BORDER, 1, TABLE_BORDER)));
label.setText((String) value);
if (isSelected) {
label.setBackground(table.getSelectionBackground());
label.setForeground(table.getSelectionForeground());
} else {
Color backgroundColor = (row % 2 == 1 ? ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR
: ColorAndFontConstants.ALTERNATE_TABLE_COLOR);
label.setBackground(backgroundColor);
label.setForeground(table.getForeground());
}
return label;
}
}
static class RightJustifiedRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 2299545L;
MultiBitLabel label = new MultiBitLabel("");
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
label.setHorizontalAlignment(SwingConstants.RIGHT);
label.setOpaque(true);
label.setBorder(new EmptyBorder(new Insets(1, TABLE_BORDER, 1, TABLE_BORDER)));
label.setText((String) value);
if (isSelected) {
label.setBackground(table.getSelectionBackground());
label.setForeground(table.getSelectionForeground());
} else {
Color backgroundColor = (row % 2 == 1 ? ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR
: ColorAndFontConstants.ALTERNATE_TABLE_COLOR);
label.setBackground(backgroundColor);
label.setForeground(table.getForeground());
}
return label;
}
}
protected void createQRCodePanel(JPanel panel, GridBagConstraints constraints) {
qrCodeLabel = new MultiBitLabel("", JLabel.CENTER);
qrCodeLabel.setVerticalTextPosition(JLabel.BOTTOM);
qrCodeLabel.setHorizontalTextPosition(JLabel.CENTER);
qrCodeLabel.setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
qrCodeLabel.setOpaque(true);
qrCodeLabel.setMinimumSize(new Dimension(QRCODE_WIDTH, QRCODE_HEIGHT));
setDragLabelTextAndTooltip();
// copy/ drag image support
if (isReceiveBitcoin()) {
qrCodeLabel.setTransferHandler(new ImageSelection(this, false));
} else {
qrCodeLabel.setTransferHandler(new ImageSelection(this, true));
}
// drag support
MouseListener listener = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent me) {
JComponent comp = (JComponent) me.getSource();
TransferHandler handler = comp.getTransferHandler();
handler.exportAsDrag(comp, me, TransferHandler.COPY);
}
};
qrCodeLabel.addMouseListener(listener);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = QR_CODE_LEFT_COLUMN;
constraints.gridy = 3;
constraints.weightx = 1;
constraints.weighty = 0.5;
constraints.gridwidth = 5;
constraints.gridheight = 3;
constraints.anchor = GridBagConstraints.BASELINE;
qrCodeScrollPane = new JScrollPane(qrCodeLabel);
qrCodeScrollPane.setOpaque(true);
qrCodeScrollPane.setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
qrCodeScrollPane.getViewport().setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
qrCodeScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
qrCodeScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
qrCodeScrollPane.setBorder(BorderFactory.createEmptyBorder());
qrCodeScrollPane.setViewportBorder(BorderFactory.createEmptyBorder());
qrCodeScrollPane.getHorizontalScrollBar().setUnitIncrement(CoreModel.SCROLL_INCREMENT);
qrCodeScrollPane.getVerticalScrollBar().setUnitIncrement(CoreModel.SCROLL_INCREMENT);
panel.add(qrCodeScrollPane, constraints);
constraints.fill = GridBagConstraints.VERTICAL;
constraints.gridx = QR_CODE_LEFT_COLUMN + 6;
constraints.gridy = 3;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.gridwidth = 5;
constraints.gridheight = 3;
constraints.anchor = GridBagConstraints.BASELINE;
JPanel verticalStent = MultiBitTitledPanel.createStent(1, QRCODE_HEIGHT);
//verticalStent.setBorder(BorderFactory.createLineBorder(Color.MAGENTA));
panel.add(verticalStent, constraints);
createQRCodeButtonPanel(panel, constraints);
}
private void setDragLabelTextAndTooltip() {
if (!isReceiveBitcoin()) {
Icon icon = qrCodeLabel.getIcon();
if (icon == null || icon.getIconHeight() == -1) {
qrCodeLabel.setText(createCenteredMultilineLabelText(controller.getLocaliser().getString("sendBitcoinPanel.dragBitcoinLabelQRcode.text")));
} else {
qrCodeLabel.setText("");
}
qrCodeLabel.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinPanel.dragBitcoinLabelQRcode.tooltip")));
}
}
protected void updateQRCodePanel() {
String address = null;
if (addressTextField != null) {
address = addressTextField.getText();
if (!WhitespaceTrimmer.trim(address).equals(address)) {
address = WhitespaceTrimmer.trim(address);
addressTextField.setText(address);
}
}
String amount = null;
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
amount = controller.getLocaliser().bitcoinValueToStringNotLocalised(parsedAmountBTC.getAmount().toBigInteger(), false, false);
}
}
String label = "";
if (labelTextArea != null) {
label = labelTextArea.getText();
}
displayQRCode(address, amount, label);
qrCodeLabel.invalidate();
upperPanel.invalidate();
qrCodeLabel.validate();
upperPanel.validate();
thisAbstractTradePanel.repaint();
}
protected void createQRCodeButtonPanel(JPanel panel, GridBagConstraints constraints) {
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridBagLayout());
buttonPanel.setOpaque(false);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = QR_CODE_LEFT_COLUMN;
constraints.gridy = 1;
constraints.weightx = 1.0;
constraints.weighty = 1.0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.BELOW_BASELINE_LEADING;
panel.add(buttonPanel, constraints);
GridBagConstraints constraints2 = new GridBagConstraints();
CopyQRCodeImageAction copyQRCodeImageAction = new CopyQRCodeImageAction(controller, this,
ImageLoader.createImageIcon(ImageLoader.COPY_ICON_FILE));
copyQRCodeImageButton = new MultiBitButton(copyQRCodeImageAction, controller);
PasteSwatchAction pasteSwatchAction = new PasteSwatchAction(this.bitcoinController, this,
ImageLoader.createImageIcon(ImageLoader.PASTE_ICON_FILE));
pasteSwatchButton = new MultiBitButton(pasteSwatchAction, controller);
qrCodeButtonPanelStent1 = MultiBitTitledPanel.createStent(smallSeparatorSize);
qrCodeButtonPanelStent2 = MultiBitTitledPanel.createStent(smallSeparatorSize);
qrCodeButtonPanelStent3 = MultiBitTitledPanel.createStent(smallSeparatorSize);
ZoomAction zoomAction = new ZoomAction(this.bitcoinController, ImageLoader.createImageIcon(ImageLoader.ZOOM_ICON_FILE), mainFrame, this);
zoomButton = new MultiBitButton(zoomAction, controller);
zoomButton.setText("");
qrCodeButtonPanelStent4 = MultiBitTitledPanel.createStent((int)zoomButton.getPreferredSize().getWidth(), (int)zoomButton.getPreferredSize().getHeight());
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 1;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 1.0;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
buttonPanel.add(qrCodeButtonPanelStent1);
constraints2.fill = GridBagConstraints.BOTH;
constraints2.gridx = 2;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 0.1;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.BELOW_BASELINE_TRAILING;
buttonPanel.add(copyQRCodeImageButton, constraints2);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 3;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 1.0;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
buttonPanel.add(qrCodeButtonPanelStent2);
constraints2.fill = GridBagConstraints.BOTH;
constraints2.gridx = 4;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 0.1;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.BELOW_BASELINE_TRAILING;
if (isReceiveBitcoin()) {
buttonPanel.add(zoomButton, constraints2);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 5;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 1.0;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
buttonPanel.add(qrCodeButtonPanelStent3, constraints2);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 6;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 1.0;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.BELOW_BASELINE_TRAILING;
buttonPanel.add(qrCodeButtonPanelStent4, constraints2);
} else {
buttonPanel.add(pasteSwatchButton, constraints2);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 5;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 1.0;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
buttonPanel.add(qrCodeButtonPanelStent3, constraints2);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 6;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 1.0;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.BELOW_BASELINE_TRAILING;
buttonPanel.add(zoomButton, constraints2);
}
JPanel forcerQR = new JPanel();
forcerQR.setOpaque(false);
constraints2.fill = GridBagConstraints.HORIZONTAL;
constraints2.gridx = 7;
constraints2.gridy = 0;
constraints2.weightx = 50.0;
constraints2.weighty = 1.0;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.LINE_START;
buttonPanel.add(forcerQR, constraints2);
}
protected JPanel createAmountPanel() {
JPanel amountPanel = new JPanel();
amountPanel.setOpaque(false);
amountPanel.applyComponentOrientation(ComponentOrientation.getOrientation(controller.getLocaliser().getLocale()));
amountPanel.setLayout(new GridBagLayout());
GridBagConstraints constraints2 = new GridBagConstraints();
int longFieldWidth = fontMetrics.stringWidth(MultiBitFrame.EXAMPLE_LONG_FIELD_TEXT);
amountBTCTextField = new MultiBitTextField("", 10, controller);
amountBTCTextField.setHorizontalAlignment(JTextField.TRAILING);
amountBTCTextField.setMinimumSize(new Dimension((int) (longFieldWidth * 0.45), getFontMetrics(
FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()
+ TEXTFIELD_VERTICAL_DELTA));
amountBTCTextField.setPreferredSize(new Dimension((int) (longFieldWidth * 0.45), getFontMetrics(
FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()
+ TEXTFIELD_VERTICAL_DELTA));
amountBTCTextField.setMaximumSize(new Dimension((int) (longFieldWidth * 0.45), getFontMetrics(
FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()
+ TEXTFIELD_VERTICAL_DELTA));
amountBTCTextField.addKeyListener(new AmountBTCKeyListener());
constraints2.fill = GridBagConstraints.HORIZONTAL;
constraints2.gridx = 0;
constraints2.gridy = 0;
constraints2.weightx = 2.0;
constraints2.weighty = 0.3;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.LINE_START;
amountPanel.add(amountBTCTextField, constraints2);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 1;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 0.1;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
amountPanel.add(MultiBitTitledPanel.createStent(3), constraints2);
MultiBitLabel amountUnitBTCLabel = new MultiBitLabel(controller.getLocaliser().getString("sendBitcoinPanel.amountUnitLabel"));
amountUnitBTCLabel.setHorizontalTextPosition(SwingConstants.LEADING);
amountUnitBTCLabel.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinPanel.amountUnitLabel.tooltip")));
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 2;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 0.3;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
amountPanel.add(amountUnitBTCLabel, constraints2);
amountEqualsLabel = new MultiBitLabel(" = "); // 3 spaces either side
amountEqualsLabel.setHorizontalTextPosition(SwingConstants.CENTER);
amountEqualsLabel.setFocusable(false);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 3;
constraints2.gridy = 0;
constraints2.weightx = 0.03;
constraints2.weighty = 0.3;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
amountPanel.add(amountEqualsLabel, constraints2);
amountPanel.add(MultiBitTitledPanel.createStent(amountEqualsLabel.getPreferredSize().width, amountEqualsLabel.getPreferredSize().height), constraints2);
amountFiatTextField = new MultiBitTextField("", 8, controller);
amountFiatTextField.setHorizontalAlignment(JTextField.TRAILING);
amountFiatTextField.setMinimumSize(new Dimension((int) (longFieldWidth * 0.2), getFontMetrics(
FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()
+ TEXTFIELD_VERTICAL_DELTA));
amountFiatTextField.setPreferredSize(new Dimension((int) (longFieldWidth * 0.2), getFontMetrics(
FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()
+ TEXTFIELD_VERTICAL_DELTA));
amountFiatTextField.setMaximumSize(new Dimension((int) (longFieldWidth * 0.2), getFontMetrics(
FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()
+ TEXTFIELD_VERTICAL_DELTA));
//amountFiatTextField.addKeyListener(new QRCodeKeyListener());
amountFiatTextField.addKeyListener(new AmountFiatKeyListener());
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = 6;
constraints2.gridy = 0;
constraints2.weightx = 1.0;
constraints2.weighty = 0.3;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.LINE_START;
amountPanel.add(amountFiatTextField, constraints2);
amountPanel.add(MultiBitTitledPanel.createStent(amountFiatTextField.getPreferredSize().width, amountFiatTextField.getPreferredSize().height), constraints2);
CurrencyInfo currencyInfo = CurrencyConverter.INSTANCE.getCurrencyCodeToInfoMap().get(CurrencyConverter.INSTANCE.getCurrencyUnit().getCurrencyCode());
if (currencyInfo == null) {
// Create a default currency info with the raw currency code as a suffix, including a separator space
currencyInfo = new CurrencyInfo(CurrencyConverter.INSTANCE.getCurrencyUnit().getCurrencyCode(), CurrencyConverter.INSTANCE.getCurrencyUnit().getCurrencyCode(), false);
currencyInfo.setHasSeparatingSpace(true);
}
amountUnitFiatLabel = new MultiBitLabel("");
int fiatCurrencySymbolPosition = 4; // Prefix is default.
int stentPosition = 5;
amountUnitFiatLabel.setText(currencyInfo.getCurrencySymbol());
if (!currencyInfo.isPrefix()) {
stentPosition = 7;
fiatCurrencySymbolPosition = 8;
}
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = stentPosition;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 0.1;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.CENTER;
amountPanel.add(MultiBitTitledPanel.createStent(3), constraints2);
amountUnitFiatLabel.setHorizontalTextPosition(SwingConstants.LEADING);
constraints2.fill = GridBagConstraints.NONE;
constraints2.gridx = fiatCurrencySymbolPosition;
constraints2.gridy = 0;
constraints2.weightx = 0.1;
constraints2.weighty = 0.3;
constraints2.gridwidth = 1;
constraints2.gridheight = 1;
constraints2.anchor = GridBagConstraints.LINE_START;
amountPanel.add(amountUnitFiatLabel, constraints2);
amountPanel.add(MultiBitTitledPanel.createStent(amountUnitFiatLabel.getPreferredSize().width, amountUnitFiatLabel.getPreferredSize().height), constraints2);
// Make fiat fields visible if currency is available.
boolean fiatIsVisible = CurrencyConverter.INSTANCE.isShowingFiat() && CurrencyConverter.INSTANCE.getRate() != null;
amountUnitFiatLabel.setVisible(fiatIsVisible);
amountFiatTextField.setVisible(fiatIsVisible);
amountEqualsLabel.setVisible(fiatIsVisible);
return amountPanel;
}
@Override
public void displayView(DisplayHint displayHint) {
if (DisplayHint.WALLET_TRANSACTIONS_HAVE_CHANGED == displayHint) {
return;
}
loadForm();
setupScrollPane();
getAddressesTableModel().fireTableDataChanged();
selectRows();
labelTextArea.setToolTipText(null);
labelTextArea.setEditable(true);
labelTextArea.setEnabled(true);
amountBTCTextField.setToolTipText(null);
amountBTCTextField.setEditable(true);
amountBTCTextField.setEnabled(true);
if (amountFiatTextField != null) {
amountFiatTextField.setToolTipText(null);
amountFiatTextField.setEditable(true);
amountFiatTextField.setEnabled(true);
}
if (createNewButton != null) {
createNewButton.setEnabled(true);
createNewButton.setToolTipText(HelpContentsPanel.createTooltipText(getLocalisationString(CREATE_NEW_TOOLTIP, null)));
}
if (deleteButton != null) {
checkDeleteSendingEnabled();
deleteButton.setToolTipText(HelpContentsPanel.createTooltipText(getLocalisationString(DELETE_TOOLTIP, null)));
}
if (pasteSwatchButton != null) {
pasteSwatchButton.setEnabled(true);
pasteSwatchButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("pasteSwatchAction.tooltip")));
}
if (CurrencyConverter.INSTANCE.isShowingFiat() && CurrencyConverter.INSTANCE.getRate() != null) {
if (amountFiatTextField != null) {
amountFiatTextField.setVisible(true);
amountEqualsLabel.setVisible(true);
amountUnitFiatLabel.setVisible(true);
}
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
if (notificationLabel != null) {
notificationLabel.setText("");
}
} else {
parsedAmountBTC = null;
if (notificationLabel != null) {
notificationLabel.setText(converterResult.getBtcMessage());
}
}
}
updateFiatAmount();
} else {
if (amountFiatTextField != null) {
amountFiatTextField.setVisible(false);
amountEqualsLabel.setVisible(false);
amountUnitFiatLabel.setVisible(false);
}
}
updateQRCodePanel();
displaySidePanel();
}
@Override
public void navigateAwayFromView() {
}
protected class QRCodeKeyListener implements KeyListener {
/** Handle the key typed event from the text field. */
@Override
public void keyTyped(KeyEvent e) {
}
/** Handle the key-pressed event from the text field. */
@Override
public void keyPressed(KeyEvent e) {
// do nothing
}
/** Handle the key-released event from the text field. */
@Override
public void keyReleased(KeyEvent e) {
String address = null;
if (addressTextField != null) {
address = addressTextField.getText();
if (!WhitespaceTrimmer.trim(address).equals(address)) {
address = WhitespaceTrimmer.trim(address);
addressTextField.setText(address);
}
}
String amount = "";
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
amount = controller.getLocaliser().bitcoinValueToStringNotLocalised(parsedAmountBTC.getAmount().toBigInteger(), false, false);
if (notificationLabel != null) {
notificationLabel.setText("");
}
} else {
parsedAmountBTC = null;
if (notificationLabel != null) {
notificationLabel.setText(converterResult.getBtcMessage());
}
}
}
String label = labelTextArea.getText();
WalletAddressBookData addressBookData = new WalletAddressBookData(label, address);
WalletInfoData walletInfo = bitcoinController.getModel().getActiveWalletWalletInfo();
if (walletInfo == null) {
walletInfo = new WalletInfoData(bitcoinController.getModel().getActiveWalletFilename(), bitcoinController.getModel().getActiveWallet(), MultiBitWalletVersion.PROTOBUF_ENCRYPTED);
bitcoinController.getModel().setActiveWalletInfo(walletInfo);
}
address = WhitespaceTrimmer.trim(address);
addressesTableModel.setAddressBookDataByRow(addressBookData, selectedAddressRowModel, isReceiveBitcoin());
selectRowInTableFromModelRow(selectedAddressRowModel);
bitcoinController.getModel().setActiveWalletPreference(thisAbstractTradePanel.getAddressConstant(), address);
bitcoinController.getModel().setActiveWalletPreference(thisAbstractTradePanel.getLabelConstant(), label);
bitcoinController.getModel().setActiveWalletPreference(thisAbstractTradePanel.getAmountConstant(), amount);
bitcoinController.getModel().getActivePerWalletModelData().setDirty(true);
displayQRCode(address, amount, label);
}
}
protected class AmountBTCKeyListener implements KeyListener {
/** Handle the key typed event in the amount BTC field */
@Override
public void keyTyped(KeyEvent e) {
}
/** Handle the key-pressed event in the amount BTC field */
@Override
public void keyPressed(KeyEvent e) {
// do nothing
}
/** Handle the key-released event in the amount BTC field */
@Override
public void keyReleased(KeyEvent e) {
String address = null;
if (addressTextField != null) {
address = addressTextField.getText();
if (!WhitespaceTrimmer.trim(address).equals(address)) {
address = WhitespaceTrimmer.trim(address);
addressTextField.setText(address);
}
}
String amount;
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
amount = controller.getLocaliser().bitcoinValueToStringNotLocalised(parsedAmountBTC.getAmount().toBigInteger(), false, false);
if (notificationLabel != null) {
notificationLabel.setText("");
}
String label = labelTextArea.getText();
bitcoinController.getModel().setActiveWalletPreference(thisAbstractTradePanel.getAmountConstant(), amount);
bitcoinController.getModel().getActivePerWalletModelData().setDirty(true);
updateFiatAmount();
displayQRCode(address, amount, label);
} else {
parsedAmountBTC = null;
if (notificationLabel != null) {
notificationLabel.setText(converterResult.getBtcMessage());
}
updateFiatAmount();
// Invalid amount o blank the QR code to avoid confusion
displayQRCode(null, null, null);
}
}
}
}
protected class AmountFiatKeyListener implements KeyListener {
/** Handle the key typed event in the amount Fiat field */
@Override
public void keyTyped(KeyEvent e) {
}
/** Handle the key-pressed event in the amount Fiat field */
@Override
public void keyPressed(KeyEvent e) {
// do nothing
}
/** Handle the key-released event in the amount Fiat field */
@Override
public void keyReleased(KeyEvent e) {
String address = null;
if (addressTextField != null) {
address = addressTextField.getText();
if (!WhitespaceTrimmer.trim(address).equals(address)) {
address = WhitespaceTrimmer.trim(address);
addressTextField.setText(address);
}
}
String label = labelTextArea.getText();
String amountFiat = amountFiatTextField.getText();
String amountBTCAsString = updateBTCAmount(amountFiat);
displayQRCode(address, amountBTCAsString, label);
}
}
protected void updateFiatAmount() {
// Convert the BTC into fiat and populate the fiat amount label.
if (CurrencyConverter.INSTANCE.getRate() != null && CurrencyConverter.INSTANCE.isShowingFiat()) {
try {
if (parsedAmountBTC != null) {
parsedAmountFiat = CurrencyConverter.INSTANCE.convertFromBTCToFiat(parsedAmountBTC.getAmount().toBigInteger());
String fiatText = CurrencyConverter.INSTANCE.getFiatAsLocalisedString(parsedAmountFiat, false, false);
if (amountFiatTextField != null) {
amountFiatTextField.setText(fiatText);
}
} else {
if (amountFiatTextField != null) {
amountFiatTextField.setText("");
}
}
} catch (NumberFormatException nfe) {
log.debug("updateFieldAmount: " + nfe.getClass().getName() + " " + nfe.getMessage());
}
}
}
protected String updateBTCAmount(String amountFiat) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.convertFromFiatToBTC(amountFiat);
if (converterResult.isFiatMoneyValid() && converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
String amountBTCAsString = controller.getLocaliser().bitcoinValueToStringNotLocalised(parsedAmountBTC.getAmount().toBigInteger(), false,
false);
bitcoinController.getModel().setActiveWalletPreference(thisAbstractTradePanel.getAmountConstant(), amountBTCAsString);
bitcoinController.getModel().getActivePerWalletModelData().setDirty(true);
amountBTCTextField.setText(CurrencyConverter.INSTANCE.getBTCAsLocalisedString(parsedAmountBTC));
if (notificationLabel != null) {
notificationLabel.setText("");
}
return amountBTCAsString;
} else {
parsedAmountBTC = null;
amountBTCTextField.setText("");
if (notificationLabel != null) {
String message = "";
if (!converterResult.isFiatMoneyValid()) {
message = converterResult.getFiatMessage();
if (message == null) {
message = "";
}
}
if (!converterResult.isBtcMoneyValid() && converterResult.getBtcMessage() != null) {
if (message.length() > 0) {
message = message + ". ";
}
message = message + converterResult.getBtcMessage();
}
notificationLabel.setText(message);
}
return null;
}
}
/**
* Display the address, amount and label as a QR code.
*/
public void displayQRCode(String address, String amount, String label) {
if (qrCodeGenerator == null) {
qrCodeGenerator = new QRCodeGenerator(this.bitcoinController);
}
try {
BufferedImage image = qrCodeGenerator.generateQRcode(address, amount, label);
ImageIcon icon;
if (image != null) {
icon = new ImageIcon(image);
} else {
icon = new ImageIcon();
}
if (qrCodeLabel != null) {
qrCodeLabel.setIcon(icon);
setDragLabelTextAndTooltip();
}
} catch (RuntimeException re) {
// QR code generation failed
log.error(re.getMessage(), re);
}
}
public boolean processDroppedImage(Image image) {
if (image == null) {
return false;
}
BufferedImage bufferedImage;
log.debug("importData - 2.1");
if (image.getWidth(qrCodeLabel) + MINIMUM_QRCODE_PANEL_HORIZONTAL_SPACING > qrCodeLabel.getWidth()
|| image.getHeight(qrCodeLabel) + MINIMUM_QRCODE_PANEL_VERTICAL_SPACING > qrCodeLabel.getHeight()) {
// scale image
double qrCodeWidth = (double) qrCodeLabel.getWidth();
double qrCodeHeight = (double) qrCodeLabel.getHeight();
double xScale = qrCodeWidth / (double) (image.getWidth(qrCodeLabel) + MINIMUM_QRCODE_PANEL_HORIZONTAL_SPACING);
double yScale = qrCodeHeight / (double) (image.getHeight(qrCodeLabel) + MINIMUM_QRCODE_PANEL_VERTICAL_SPACING);
double scaleFactor = Math.min(xScale, yScale);
bufferedImage = toBufferedImage(image, (int) (image.getWidth(qrCodeLabel) * scaleFactor),
(int) (image.getHeight(qrCodeLabel) * scaleFactor));
} else {
// no resize
bufferedImage = toBufferedImage(image, -1, -1);
}
log.debug("importData - 2.2");
ImageIcon icon = new ImageIcon(bufferedImage);
// decode the QRCode to a String
QRCodeEncoderDecoder qrCodeEncoderDecoder = new QRCodeEncoderDecoder(image.getWidth(qrCodeLabel),
image.getHeight(qrCodeLabel));
log.debug("importData - 2.3");
String decodedString = qrCodeEncoderDecoder.decode(toBufferedImage(image, -1, -1));
log.debug("importData - 3 - decodedResult = {}", decodedString);
log.info("importData = decodedString = {}", decodedString);
return processDecodedString(decodedString, icon);
}
public boolean processDecodedString(String decodedString, ImageIcon icon) {
// check to see if the wallet files have changed
WalletData perWalletModelData = this.bitcoinController.getModel().getActivePerWalletModelData();
// decode the string to an WalletAddressBookData
// Early MultiBit versions did not URL encode the label hence may
// have illegal embedded spaces - convert to ENCODED_SPACE_CHARACTER
// i.e be lenient
String uriString = decodedString.replace(" ", BitcoinController.ENCODED_SPACE_CHARACTER);
BitcoinURI bitcoinURI;
try {
bitcoinURI = new BitcoinURI(this.bitcoinController.getModel().getNetworkParameters(), uriString);
} catch (BitcoinURIParseException e) {
Message message = new Message(e.getClass().getName() + " " + e.getMessage());
MessageManager.INSTANCE.addMessage(message);
return false;
}
log.debug("AbstractTradePanel - ping 1");
Address address = bitcoinURI.getAddress();
log.debug("AbstractTradePanel - ping 2");
String addressString = address.toString();
log.debug("AbstractTradePanel - ping 3");
String amountString = "";
String amountStringLocalised = "";
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
amountString = controller.getLocaliser().bitcoinValueToStringNotLocalised(parsedAmountBTC.getAmount().toBigInteger(), false, false);
amountStringLocalised = CurrencyConverter.INSTANCE.getBTCAsLocalisedString(parsedAmountBTC);
} else {
parsedAmountBTC = null;
if (notificationLabel != null) {
notificationLabel.setText(converterResult.getBtcMessage());
}
}
}
if (bitcoinURI.getAmount() != null) {
amountString = controller.getLocaliser().bitcoinValueToStringNotLocalised(bitcoinURI.getAmount(), false, false);
parsedAmountBTC = Money.of(CurrencyConverter.INSTANCE.BITCOIN_CURRENCY_UNIT, new BigDecimal(bitcoinURI.getAmount()));
amountStringLocalised = CurrencyConverter.INSTANCE.getBTCAsLocalisedString(parsedAmountBTC);
}
log.debug("AbstractTradePanel - ping 4");
String decodedLabel = "";
try {
if (bitcoinURI.getLabel() != null) {
decodedLabel = java.net.URLDecoder.decode(bitcoinURI.getLabel(), "UTF-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
log.debug("AbstractTradePanel#processDecodedString addressString = " + addressString + ", amountString = " + amountString
+ ", label = " + decodedLabel);
log.debug("AbstractTradePanel - ping 5");
WalletAddressBookData addressBookData = new WalletAddressBookData(decodedLabel, addressString);
log.debug("AbstractTradePanel - ping 6");
// see if the address is already in the address book
// see if the current address is on the table and
// select it
int rowToSelectModel = addressesTableModel.findRowByAddress(addressBookData.getAddress(), false);
if (rowToSelectModel >= 0) {
addressesTableModel.setAddressBookDataByRow(addressBookData, rowToSelectModel, false);
selectedAddressRowModel = rowToSelectModel;
selectRowInTableFromModelRow(rowToSelectModel);
} else {
// add a new row to the table
this.bitcoinController.getModel().getActiveWalletWalletInfo().addSendingAddress(addressBookData);
this.bitcoinController.getModel().getActivePerWalletModelData().setDirty(true);
addressesTableModel.fireTableDataChanged();
// select new row
rowToSelectModel = addressesTableModel.findRowByAddress(addressBookData.getAddress(), false);
if (rowToSelectModel >= 0) {
selectedAddressRowModel = rowToSelectModel;
selectRowInTableFromModelRow(rowToSelectModel);
}
}
addressesTable.invalidate();
addressesTable.validate();
addressesTable.repaint();
mainFrame.invalidate();
mainFrame.validate();
mainFrame.repaint();
log.debug("AbstractTradePanel - ping 7");
this.bitcoinController.getModel().setActiveWalletPreference(BitcoinModel.SEND_ADDRESS, addressString);
log.debug("AbstractTradePanel - ping 8");
this.bitcoinController.getModel().setActiveWalletPreference(BitcoinModel.SEND_LABEL, decodedLabel);
log.debug("AbstractTradePanel - ping 9");
this.bitcoinController.getModel().setActiveWalletPreference(BitcoinModel.SEND_AMOUNT, amountString);
log.debug("AbstractTradePanel - ping 10");
addressTextField.setText(addressString);
log.debug("AbstractTradePanel - ping 11");
amountBTCTextField.setText(amountStringLocalised);
log.debug("AbstractTradePanel - ping 12");
labelTextArea.setText(decodedLabel);
log.debug("AbstractTradePanel - ping 13");
updateFiatAmount();
log.debug("AbstractTradePanel - ping 14");
Message message = new Message("");
MessageManager.INSTANCE.addMessage(message);
if (icon != null) {
qrCodeLabel.setIcon(icon);
setDragLabelTextAndTooltip();
} else {
displayQRCode(addressString, amountString, decodedLabel);
}
checkDeleteSendingEnabled();
return true;
}
/**
* select the rows that correspond to the current data
*/
public void selectRows() {
// stop listener firing
addressesListener.setEnabled(false);
String address = this.bitcoinController.getModel().getActiveWalletPreference(getAddressConstant());
String amount = "";
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
amount = controller.getLocaliser().bitcoinValueToStringNotLocalised(parsedAmountBTC.getAmount().toBigInteger(), false, false);
}
}
displayQRCode(address, amount, labelTextArea.getText());
// see if the current address is on the table and select it
int rowToSelectModel = addressesTableModel.findRowByAddress(address, isReceiveBitcoin());
if (rowToSelectModel >= 0) {
selectedAddressRowModel = rowToSelectModel;
selectRowInTableFromModelRow(rowToSelectModel);
}
addressesTable.invalidate();
addressesTable.validate();
addressesTable.repaint();
// enable listener
addressesListener.setEnabled(true);
}
private void selectRowInTableFromModelRow(int rowToSelectModel) {
if (rowToSelectModel < addressesTableModel.getRowCount()) {
try {
int rowToSelect = addressesTable.convertRowIndexToView(rowToSelectModel);
addressesListener.setEnabled(false);
addressesTable.getSelectionModel().setSelectionInterval(rowToSelect, rowToSelect);
addressesListener.setEnabled(true);
// scroll to visible
addressesTable.scrollRectToVisible(addressesTable.getCellRect(rowToSelect, 0, false));
} catch (ArrayIndexOutOfBoundsException e) {
// absorb - row wrong
}
}
}
public JTextArea getLabelTextArea() {
return labelTextArea;
}
private BufferedImage toBufferedImage(Image image, int width, int height) {
log.debug("toBufferedImage - 1");
if (image == null) {
return null;
}
if (width == -1) {
width = image.getWidth(null);
}
if (height == -1) {
height = image.getHeight(null);
}
// draw original image to thumbnail image object and
// scale it to the new size on-the-fly
log.debug("toBufferedImage - 2.2, image = {} ,width = {}, height = {}", new Object[] { image, width, height });
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
log.debug("toBufferedImage - 2.3, bufferedImage = {}", bufferedImage);
Graphics2D g2 = bufferedImage.createGraphics();
log.debug("toBufferedImage - 3");
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(image, 0, 0, width, height, null);
log.debug("toBufferedImage - 4");
g2.dispose();
return bufferedImage;
}
public AddressBookTableModel getAddressesTableModel() {
return addressesTableModel;
}
public JTable getAddressesTable() {
return addressesTable;
}
private String createCenteredMultilineLabelText(String labelText) {
StringBuilder centeredText = new StringBuilder("<html><center>");
String[] lines = labelText.split("\\|");
if (lines != null) {
for (int i = 0; i < lines.length ; i++) {
if ( i > 0) {
centeredText.append("<br>");
}
centeredText.append(lines[i]);
}
}
centeredText.append("</center></html>");
return centeredText.toString();
}
// CopyQRCodeImageDataProvider methods
@Override
public JLabel getURIImage() {
return qrCodeLabel;
}
@Override
public String getAddress() {
if (addressTextField != null) {
String address = addressTextField.getText();
return WhitespaceTrimmer.trim(address);
} else {
return null;
}
}
@Override
public String getLabel() {
if (labelTextArea != null) {
return labelTextArea.getText();
} else {
return null;
}
}
@Override
public String getAmount() {
String amount = null;
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
amount = controller.getLocaliser().bitcoinValueToStringNotLocalised(converterResult.getBtcMoney().getAmount().toBigInteger(), false, false);
}
}
return amount;
}
@Override
public String getAmountFiat() {
if (amountFiatTextField != null) {
return amountFiatTextField.getText();
} else {
return null;
}
}
public MultiBitTextField getAddressTextField() {
return addressTextField;
}
@Override
public void lostExchangeRate(ExchangeRate exchangeRate) {
// TODO Auto-generated method stub
}
@Override
public void foundExchangeRate(ExchangeRate exchangeRate) {
updatedExchangeRate(exchangeRate);
}
@Override
public void updatedExchangeRate(ExchangeRate exchangeRate) {
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
// Make fiat fields visible if currency is available.
boolean fiatIsVisible = CurrencyConverter.INSTANCE.isShowingFiat() && CurrencyConverter.INSTANCE.getRate() != null;
if (amountUnitFiatLabel != null) {
amountUnitFiatLabel.setVisible(fiatIsVisible);
}
if (amountFiatTextField != null) {
amountFiatTextField.setVisible(fiatIsVisible);
}
if (amountEqualsLabel != null) {
amountEqualsLabel.setVisible(fiatIsVisible);
}
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTC(amountBTCTextField.getText());
if (converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
updateFiatAmount();
}
// If the conversion fails this is probably an error in one the amount fields so just leave it.
}
}});
}
}