/**
* Copyright 2013 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.core.AddressFormatException;
import com.google.bitcoin.core.Utils;
import org.multibit.controller.bitcoin.BitcoinController;
import org.multibit.exchange.CurrencyConverter;
import org.multibit.exchange.CurrencyConverterResult;
import org.multibit.model.bitcoin.BitcoinModel;
import org.multibit.model.bitcoin.WalletAddressBookData;
import org.multibit.model.core.CoreModel;
import org.multibit.utils.ImageLoader;
import org.multibit.viewsystem.DisplayHint;
import org.multibit.viewsystem.View;
import org.multibit.viewsystem.Viewable;
import org.multibit.viewsystem.swing.ColorAndFontConstants;
import org.multibit.viewsystem.swing.MultiBitFrame;
import org.multibit.viewsystem.swing.action.*;
import org.multibit.viewsystem.swing.view.components.*;
import org.multibit.viewsystem.swing.view.models.AddressBookTableModel;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
public class SendBitcoinPanel extends AbstractTradePanel implements Viewable {
private static final long serialVersionUID = -2065108865497111662L;
private static SendBitcoinConfirmAction sendBitcoinConfirmAction;
private static boolean enableSendButton = false;
private static MultiBitButton sendButton;
private MultiBitButton pasteAddressButton;
private static SendBitcoinPanel thisPanel;
private static String regularTooltipText = "";
private static String pleaseWaitTooltipText = "";
public SendBitcoinPanel(BitcoinController bitcoinController, MultiBitFrame mainFrame) {
super(mainFrame, bitcoinController);
thisPanel = this;
checkDeleteSendingEnabled();
regularTooltipText = controller.getLocaliser().getString("sendBitcoinAction.tooltip");
pleaseWaitTooltipText = controller.getLocaliser().getString("sendBitcoinAction.pleaseWait.tooltip");
}
public static void setEnableSendButton(boolean enableSendButton) {
SendBitcoinPanel.enableSendButton = enableSendButton;
if (EventQueue.isDispatchThread()) {
enableSendButtonOnSwingThread();
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
enableSendButtonOnSwingThread();
}
});
}
}
private static void enableSendButtonOnSwingThread() {
if (sendBitcoinConfirmAction != null) {
sendBitcoinConfirmAction.setEnabled(SendBitcoinPanel.enableSendButton);
}
final String finalRegularTooltipText = regularTooltipText;
final String finalPleaseWaitTooltipText = pleaseWaitTooltipText;
if (sendButton != null) {
if (SendBitcoinPanel.enableSendButton) {
sendButton.setEnabled(true);
sendButton.setToolTipText(HelpContentsPanel.createTooltipText(finalRegularTooltipText));
} else {
sendButton.setEnabled(false);
sendButton.setToolTipText(HelpContentsPanel.createTooltipText(finalPleaseWaitTooltipText));
}
}
if (thisPanel != null) {
thisPanel.invalidate();
thisPanel.validate();
thisPanel.repaint();
}
}
@Override
protected boolean isReceiveBitcoin() {
return false;
}
@Override
public Action getCreateNewAddressAction() {
return new CreateNewSendingAddressAction(super.bitcoinController, this);
}
@Override
protected Action getDeleteAddressAction() {
if (deleteAddressAction == null) {
return new DeleteSendingAddressAction(this.bitcoinController, mainFrame, this);
} else {
return deleteAddressAction;
}
}
@Override
public void checkDeleteSendingEnabled() {
AddressBookTableModel addressesTableModel = getAddressesTableModel();
if (deleteAddressAction != null) {
deleteAddressAction.setEnabled(addressesTableModel != null && addressesTableModel.getRowCount() > 0);
}
}
@Override
public String getAddressConstant() {
return BitcoinModel.SEND_ADDRESS;
}
@Override
public String getLabelConstant() {
return BitcoinModel.SEND_LABEL;
}
@Override
public String getAmountConstant() {
return BitcoinModel.SEND_AMOUNT;
}
/**
* method for concrete impls to populate the localisation map
*/
@Override
protected void populateLocalisationMap() {
localisationKeyConstantToKeyMap.put(ADDRESSES_TITLE, "sendBitcoinPanel.sendingAddressesTitle");
localisationKeyConstantToKeyMap.put(CREATE_NEW_TOOLTIP, "createOrEditAddressAction.createSending.tooltip");
localisationKeyConstantToKeyMap.put(DELETE_TOOLTIP, "deleteSendingAddressSubmitAction.tooltip");
}
@Override
protected JPanel createFormPanel(JPanel formPanel, GridBagConstraints constraints) {
formPanel.setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
JPanel buttonPanel = new JPanel();
FlowLayout flowLayout = new FlowLayout();
flowLayout.setAlignment(FlowLayout.LEADING);
buttonPanel.setLayout(flowLayout);
formPanel.setLayout(new GridBagLayout());
// create stents and forcers
createFormPanelStentsAndForcers(formPanel, constraints);
MultiBitLabel addressLabel = new MultiBitLabel(controller.getLocaliser().getString("sendBitcoinPanel.addressLabel"));
addressLabel.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinPanel.addressLabel.tooltip")));
addressLabel.setHorizontalAlignment(JLabel.TRAILING);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 1;
constraints.weightx = 4.0;
constraints.weighty = 0.2;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.LINE_END;
formPanel.add(addressLabel, constraints);
String receiveAddressText = controller.getLocaliser().getString("receiveBitcoinPanel.addressLabel");
MultiBitLabel notUsedReceiveAddressLabel = new MultiBitLabel(receiveAddressText);
formPanel.add(MultiBitTitledPanel.createStent((int) notUsedReceiveAddressLabel.getPreferredSize().getWidth()), constraints);
int longFieldWidth = fontMetrics.stringWidth(MultiBitFrame.EXAMPLE_LONG_FIELD_TEXT);
addressTextField = new MultiBitTextField("", 24, controller);
addressTextField.setHorizontalAlignment(JTextField.LEADING);
addressTextField.setMinimumSize(new Dimension(longFieldWidth, getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont())
.getHeight() + TEXTFIELD_VERTICAL_DELTA));
addressTextField.setPreferredSize(new Dimension(longFieldWidth, getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont())
.getHeight() + TEXTFIELD_VERTICAL_DELTA));
addressTextField.setMaximumSize(new Dimension(longFieldWidth, getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont())
.getHeight() + TEXTFIELD_VERTICAL_DELTA));
addressTextField.addKeyListener(new QRCodeKeyListener());
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 2;
constraints.gridy = 1;
constraints.weightx = 1.0;
constraints.weighty = 0.2;
constraints.gridwidth = 3;
constraints.anchor = GridBagConstraints.LINE_START;
formPanel.add(addressTextField, constraints);
ImageIcon copyIcon = ImageLoader.createImageIcon(ImageLoader.COPY_ICON_FILE);
CopySendAddressAction copyAddressAction = new CopySendAddressAction(controller, this, copyIcon);
MultiBitButton copyAddressButton = new MultiBitButton(copyAddressAction, controller);
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 6;
constraints.gridy = 1;
constraints.weightx = 1;
constraints.gridwidth = 1;
constraints.anchor = GridBagConstraints.LINE_START;
formPanel.add(copyAddressButton, constraints);
ImageIcon pasteIcon = ImageLoader.createImageIcon(ImageLoader.PASTE_ICON_FILE);
PasteAddressAction pasteAddressAction = new PasteAddressAction(super.bitcoinController, this, pasteIcon);
pasteAddressButton = new MultiBitButton(pasteAddressAction, controller);
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 8;
constraints.gridy = 1;
constraints.weightx = 10.0;
constraints.weighty = 0.2;
constraints.gridwidth = 1;
constraints.anchor = GridBagConstraints.LINE_START;
formPanel.add(pasteAddressButton, constraints);
MultiBitLabel labelLabel = new MultiBitLabel(controller.getLocaliser().getString("sendBitcoinPanel.labelLabel"));
labelLabel.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinPanel.labelLabel.tooltip")));
labelLabel.setHorizontalAlignment(JLabel.TRAILING);
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 0;
constraints.gridy = 3;
constraints.weightx = 0.1;
constraints.weighty = 1.0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.LINE_END;
formPanel.add(labelLabel, constraints);
JTextField aTextField = new JTextField();
labelTextArea = new MultiBitTextArea("", AbstractTradePanel.PREFERRED_NUMBER_OF_LABEL_ROWS, 20, controller);
labelTextArea.setBorder(aTextField.getBorder());
labelTextArea.addKeyListener(new QRCodeKeyListener());
final JScrollPane labelScrollPane = new JScrollPane(labelTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
labelScrollPane.setOpaque(true);
labelScrollPane.setBackground(ColorAndFontConstants.VERY_LIGHT_BACKGROUND_COLOR);
labelScrollPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
labelScrollPane.getViewport().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (labelScrollPane.getVerticalScrollBar().isVisible()) {
labelScrollPane.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.LIGHT_GRAY));
} else {
labelScrollPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
}
}
});
labelScrollPane.setMinimumSize(new Dimension(longFieldWidth, getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont())
.getHeight() * AbstractTradePanel.PREFERRED_NUMBER_OF_LABEL_ROWS + TEXTFIELD_VERTICAL_DELTA + 6));
labelScrollPane.setPreferredSize(new Dimension(longFieldWidth, getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont())
.getHeight() * AbstractTradePanel.PREFERRED_NUMBER_OF_LABEL_ROWS + TEXTFIELD_VERTICAL_DELTA + 6));
labelScrollPane.getHorizontalScrollBar().setUnitIncrement(CoreModel.SCROLL_INCREMENT);
labelScrollPane.getVerticalScrollBar().setUnitIncrement(CoreModel.SCROLL_INCREMENT);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 2;
constraints.gridy = 3;
constraints.weightx = 0.6;
constraints.weighty = 1.0;
constraints.gridwidth = 3;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.LINE_START;
formPanel.add(labelScrollPane, constraints);
MultiBitLabel amountLabel = new MultiBitLabel(controller.getLocaliser().getString("sendBitcoinPanel.amountLabel"));
amountLabel.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinPanel.amountLabel.tooltip")));
amountLabel.setHorizontalAlignment(JLabel.TRAILING);
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 0;
constraints.gridy = 5;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0.1;
constraints.weighty = 0.20;
constraints.anchor = GridBagConstraints.LINE_END;
formPanel.add(amountLabel, constraints);
JPanel amountPanel = createAmountPanel();
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 2;
constraints.gridy = 5;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0.1;
constraints.weighty = 0.20;
constraints.anchor = GridBagConstraints.LINE_START;
formPanel.add(amountPanel, constraints);
notificationLabel = new MultiBitLabel("");
notificationLabel.setForeground(Color.RED);
//notificationLabel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 2;
constraints.gridy = 6;
constraints.gridwidth = 8;
constraints.gridheight = 3;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.anchor = GridBagConstraints.ABOVE_BASELINE_LEADING;
formPanel.add(notificationLabel, constraints);
Action helpAction;
if (ComponentOrientation.LEFT_TO_RIGHT == ComponentOrientation.getOrientation(controller.getLocaliser().getLocale())) {
helpAction = new HelpContextAction(controller, ImageLoader.HELP_CONTENTS_BIG_ICON_FILE,
"multiBitFrame.helpMenuText", "multiBitFrame.helpMenuTooltip", "multiBitFrame.helpMenuText",
HelpContentsPanel.HELP_SENDING_URL);
} else {
helpAction = new HelpContextAction(controller, ImageLoader.HELP_CONTENTS_BIG_RTL_ICON_FILE,
"multiBitFrame.helpMenuText", "multiBitFrame.helpMenuTooltip", "multiBitFrame.helpMenuText",
HelpContentsPanel.HELP_SENDING_URL);
}
HelpButton helpButton = new HelpButton(helpAction, controller);
helpButton.setText("");
String tooltipText = HelpContentsPanel.createMultilineTooltipText(new String[]{
controller.getLocaliser().getString("sendBitcoinPanel.helpLabel1.message"),
controller.getLocaliser().getString("sendBitcoinPanel.helpLabel2.message"),
controller.getLocaliser().getString("sendBitcoinPanel.helpLabel3.message"), "\n",
controller.getLocaliser().getString("multiBitFrame.helpMenuTooltip")});
helpButton.setToolTipText(tooltipText);
helpButton.setHorizontalAlignment(SwingConstants.LEADING);
helpButton.setBorder(BorderFactory.createEmptyBorder(0, HELP_BUTTON_INDENT, HELP_BUTTON_INDENT, HELP_BUTTON_INDENT));
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 8;
constraints.weightx = 1;
constraints.weighty = 0.3;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.BELOW_BASELINE_LEADING;
formPanel.add(helpButton, constraints);
sendBitcoinConfirmAction = new SendBitcoinConfirmAction(super.bitcoinController, mainFrame, this);
sendBitcoinConfirmAction.setEnabled(enableSendButton);
sendButton = new MultiBitButton(sendBitcoinConfirmAction, controller);
if (enableSendButton) {
sendButton.setEnabled(true);
sendButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinAction.tooltip")));
} else {
sendButton.setEnabled(false);
sendButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinAction.pleaseWait.tooltip")));
}
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 6;
constraints.gridy = 5;
constraints.weightx = 0.1;
constraints.weighty = 0.1;
constraints.gridwidth = 3;
constraints.gridheight = 1;
constraints.anchor = GridBagConstraints.LINE_START;
formPanel.add(sendButton, constraints);
Action sidePanelAction = new MoreOrLessAction(controller, this);
sidePanelButton = new MultiBitButton(sidePanelAction, controller);
sidePanelButton.setBorder(BorderFactory.createEmptyBorder());
sidePanelButton.setBorderPainted(false);
sidePanelButton.setFocusPainted(false);
sidePanelButton.setContentAreaFilled(false);
displaySidePanel();
constraints.fill = GridBagConstraints.NONE;
constraints.gridx = 4;
constraints.gridy = 3;
constraints.weightx = 0.1;
constraints.weighty = 0.3;
constraints.gridwidth = 7;
constraints.gridheight = 3;
constraints.anchor = GridBagConstraints.BASELINE_TRAILING;
formPanel.add(sidePanelButton, constraints);
return formPanel;
}
@Override
public String getAddress() {
if (addressTextField != null) {
return addressTextField.getText();
} else {
return "";
}
}
@Override
public void loadForm() {
// get the current address, label and amount from the model
String address = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.SEND_ADDRESS);
String label = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.SEND_LABEL);
String amountNotLocalised = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.SEND_AMOUNT);
if (amountBTCTextField != null) {
CurrencyConverterResult converterResult = CurrencyConverter.INSTANCE.parseToBTCNotLocalised(amountNotLocalised);
if (converterResult.isBtcMoneyValid()) {
parsedAmountBTC = converterResult.getBtcMoney();
String amountLocalised = CurrencyConverter.INSTANCE.getBTCAsLocalisedString(converterResult.getBtcMoney());
amountBTCTextField.setText(amountLocalised);
if (notificationLabel != null) {
notificationLabel.setText("");
}
} else {
parsedAmountBTC = null;
amountBTCTextField.setText("");
if (notificationLabel != null) {
notificationLabel.setText(converterResult.getBtcMessage());
}
}
}
if (address != null) {
addressTextField.setText(address);
} else {
addressTextField.setText("");
}
if (label != null) {
labelTextArea.setText(label);
} else {
labelTextArea.setText("");
}
// if there is a pending 'handleopenURI' that needs pasting into the
// send form, do it
String performPasteNow = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.SEND_PERFORM_PASTE_NOW);
if (Boolean.TRUE.toString().equalsIgnoreCase(performPasteNow)) {
try {
Address decodeAddress = new Address(this.bitcoinController.getModel().getNetworkParameters(), address);
processDecodedString(com.google.bitcoin.uri.BitcoinURI.convertToBitcoinURI(decodeAddress, Utils.toNanoCoins(amountNotLocalised), label, null), null);
this.bitcoinController.getModel().setActiveWalletPreference(BitcoinModel.SEND_PERFORM_PASTE_NOW, "false");
sendButton.requestFocusInWindow();
mainFrame.bringToFront();
} catch (AddressFormatException e) {
throw new RuntimeException(e);
}
}
}
public void setAddressBookDataByRow(WalletAddressBookData addressBookData) {
addressTextField.setText(addressBookData.getAddress());
addressesTableModel.setAddressBookDataByRow(addressBookData, selectedAddressRowModel, false);
}
@Override
public void displayView(DisplayHint displayHint) {
super.displayView(displayHint);
if (DisplayHint.WALLET_TRANSACTIONS_HAVE_CHANGED == displayHint) {
return;
}
JTextField aTextField = new JTextField();
labelTextArea.setBorder(aTextField.getBorder());
String bringToFront = controller.getModel().getUserPreference(BitcoinModel.BRING_TO_FRONT);
if (Boolean.TRUE.toString().equals(bringToFront)) {
controller.getModel().setUserPreference(BitcoinModel.BRING_TO_FRONT, "false");
mainFrame.bringToFront();
}
addressTextField.setToolTipText(null);
addressTextField.setEditable(true);
addressTextField.setEnabled(true);
if (sendButton != null) {
if (SendBitcoinPanel.enableSendButton) {
sendButton.setEnabled(true);
sendButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinAction.tooltip")));
} else {
sendButton.setEnabled(false);
sendButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("sendBitcoinAction.pleaseWait.tooltip")));
}
}
if (pasteAddressButton != null) {
pasteAddressButton.setEnabled(true);
pasteAddressButton.setToolTipText(HelpContentsPanel.createTooltipText(controller.getLocaliser().getString("pasteAddressAction.tooltip")));
}
titleLabel.setText(controller.getLocaliser().getString("sendBitcoinPanel.sendingAddressesTitle"));
titleLabel.setToolTipText(null);
checkDeleteSendingEnabled();
}
@Override
public Icon getViewIcon() {
return ImageLoader.createImageIcon(ImageLoader.SEND_BITCOIN_ICON_FILE);
}
@Override
public String getViewTitle() {
return controller.getLocaliser().getString("sendBitcoinConfirmAction.text");
}
@Override
public String getViewTooltip() {
return controller.getLocaliser().getString("sendBitcoinConfirmAction.tooltip");
}
@Override
public View getViewId() {
return View.SEND_BITCOIN_VIEW;
}
public SendBitcoinConfirmAction getSendBitcoinConfirmAction() {
return sendBitcoinConfirmAction;
}
}