/* * * Copyright 2014 http://Bither.net * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * / */ package net.bither.viewsystem.froms; import net.bither.Bither; import net.bither.BitherSetting; import net.bither.BitherUI; import net.bither.bitherj.core.Address; import net.bither.bitherj.core.AddressManager; import net.bither.bitherj.core.Tx; import net.bither.bitherj.crypto.SecureCharSequence; import net.bither.bitherj.utils.GenericUtils; import net.bither.bitherj.utils.UnitUtil; import net.bither.bitherj.utils.Utils; import net.bither.fonts.AwesomeDecorator; import net.bither.fonts.AwesomeIcon; import net.bither.languages.MessageKey; import net.bither.qrcode.IReadQRCode; import net.bither.qrcode.IScanQRCode; import net.bither.qrcode.SelectQRCodePanel; import net.bither.runnable.CommitTransactionThread; import net.bither.runnable.CompleteTransactionRunnable; import net.bither.runnable.RCheckRunnable; import net.bither.runnable.RunnableListener; import net.bither.utils.InputParser; import net.bither.utils.LocaliserUtils; import net.bither.viewsystem.TextBoxes; import net.bither.viewsystem.action.PasteAddressAction; import net.bither.viewsystem.base.Buttons; import net.bither.viewsystem.base.Labels; import net.bither.viewsystem.base.Panels; import net.bither.viewsystem.dialogs.MessageDialog; import net.bither.viewsystem.froms.SendBitcoinConfirmPanel.SendConfirmListener; import net.bither.viewsystem.themes.Themes; import net.miginfocom.swing.MigLayout; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.event.ActionEvent; public class SendBitcoinPanel extends WizardPanel implements SelectAddressPanel.SelectAddressListener { protected JTextField tfAmt; protected JPasswordField currentPassword; protected JTextField tfAddress; protected JButton btnChangeAddress; private String bitcoinAddress; private JLabel spinner; private String changeAddress = ""; protected String doateAddress; public SendBitcoinPanel() { this(null); } public SendBitcoinPanel(String doateAddress) { super(MessageKey.SEND, AwesomeIcon.SEND); this.doateAddress = doateAddress; setOkAction(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { onSend(); } }); } @Override public void initialiseContent(JPanel panel) { panel.setLayout(new MigLayout( Panels.migXYLayout(), "[]", // Column constraints "[][][][][]" // Row constraints )); JLabel label = Labels.newValueLabel(LocaliserUtils.getString("address_balance") + " : " + Utils.bitcoinValueToPlainString(Bither.getActionAddress().getBalance())); panel.add(label, "align center,wrap"); panel.add(newEnterAddressPanel(), "push,wrap"); panel.add(newAmountPanel(), "push,wrap"); panel.add(getenterPasswordMaV(), "push"); if (!Utils.isEmpty(this.doateAddress)) { tfAddress.setText(this.doateAddress); } validateValues(); } public JPanel newAmountPanel() { JPanel panel = Panels.newPanel(new MigLayout( Panels.migXLayout(), "[][][][]", // Columns "[]" // Rows )); //panel.add(Labels.newAmount(), "span 4,grow,push,wrap"); JLabel label = Labels.newBitcoinSymbol(); label.setText(""); AwesomeDecorator.applyIcon(AwesomeIcon.FA_BTC, label, true, BitherUI.NORMAL_ICON_SIZE); tfAmt = TextBoxes.newAmount(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { updateUI(); } @Override public void removeUpdate(DocumentEvent e) { updateUI(); } @Override public void changedUpdate(DocumentEvent e) { updateUI(); } private void updateUI() { validateValues(); } }); panel.add(label, "shrink"); panel.add(tfAmt, "grow,push,wrap"); return panel; } public JPanel newEnterAddressPanel() { JPanel panel = Panels.newPanel( new MigLayout( Panels.migXLayout(), "[][][][]", // Columns "[]" // Rows )); tfAddress = TextBoxes.newEnterAddress(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { updateUI(); } @Override public void removeUpdate(DocumentEvent e) { updateUI(); } @Override public void changedUpdate(DocumentEvent e) { updateUI(); } private void updateUI() { validateValues(); } }); panel.add(Labels.newBitcoinAddress()); panel.add(tfAddress, "growx," + BitherUI.COMBO_BOX_WIDTH_MIG + ",push"); panel.add(Buttons.newPasteButton(new PasteAddressAction(tfAddress)), "shrink"); panel.add(getQRCodeButton(), "shrink"); btnChangeAddress = Buttons.newOptionsButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { String defaultAddress = changeAddress; if (Utils.isEmpty(defaultAddress)) { defaultAddress = Bither.getActionAddress().getAddress(); } SelectAddressPanel selectAddressPanel = new SelectAddressPanel(SendBitcoinPanel.this, AddressManager.getInstance().getAllAddresses(), defaultAddress); selectAddressPanel.updateTitle(LocaliserUtils.getString("select_change_address_option_name")); selectAddressPanel.showPanel(); } }); panel.add(btnChangeAddress, "shrink"); return panel; } protected void onSend() { bitcoinAddress = tfAddress.getText().trim(); if (Utils.validBicoinAddress(bitcoinAddress)) { if (Utils.compareString(bitcoinAddress, changeAddress)) { new MessageDialog(LocaliserUtils.getString("select_change_address_change_to_same_warn")).showMsg(); return; } String amtString = tfAmt.getText().trim(); long btc = GenericUtils.toNanoCoins(amtString, 0).longValue(); try { SecureCharSequence secureCharSequence = new SecureCharSequence(currentPassword.getPassword()); CompleteTransactionRunnable completeTransactionRunnable = new CompleteTransactionRunnable( Bither.getActionAddress(), btc, bitcoinAddress, changeAddress, secureCharSequence); completeTransactionRunnable.setRunnableListener(completeTransactionListener); new Thread(completeTransactionRunnable).start(); } catch (Exception e) { e.printStackTrace(); } } } RunnableListener completeTransactionListener = new RunnableListener() { @Override public void prepare() { } @Override public void success(Object obj) { Tx tx = (Tx) obj; RCheckRunnable run = new RCheckRunnable(Bither.getActionAddress(), tx); run.setRunnableListener(rcheckHandler); new Thread(run).start(); } @Override public void error(int errorCode, String errorMsg) { new MessageDialog(errorMsg).showMsg(); } }; SendConfirmListener sendConfirmListener = new SendConfirmListener() { @Override public void onConfirm(Tx request) { onCancel(); sendTx(request); } @Override public void onCancel() { } }; private RunnableListener rcheckHandler = new RunnableListener() { @Override public void prepare() { } @Override public void success(Object obj) { final Tx tx = (Tx) obj; SendBitcoinConfirmPanel sendBitcoinConfirmPanel = new SendBitcoinConfirmPanel(sendConfirmListener, bitcoinAddress, changeAddress, tx); sendBitcoinConfirmPanel.showPanel(); } @Override public void error(int errorCode, String errorMsg) { } }; private void sendTx(Tx tx) { try { CommitTransactionThread commitTransactionThread = new CommitTransactionThread(Bither.getActionAddress(), tx , true, commitTransactionListener); commitTransactionThread.start(); } catch (Exception e) { e.printStackTrace(); } } CommitTransactionThread.CommitTransactionListener commitTransactionListener = new CommitTransactionThread.CommitTransactionListener() { @Override public void onCommitTransactionSuccess(Tx tx) { closePanel(); if (Utils.isEmpty(doateAddress)) { new MessageDialog(LocaliserUtils.getString("send_success")).showMsg(); } else { new MessageDialog(LocaliserUtils.getString("donate_thanks")).showMsg(); } } @Override public void onCommitTransactionFailed() { new MessageDialog(LocaliserUtils.getString("send_failed")).showMsg(); } }; private JButton getQRCodeButton() { JButton button = Buttons.newFromCameraIconButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { SelectQRCodePanel qrCodePanel = new SelectQRCodePanel(new IScanQRCode() { public void handleResult(final String result, final IReadQRCode readQRCode) { new InputParser.StringInputParser(result) { @Override protected void bitcoinRequest(final String address, final String addressLabel, final long amount, final String bluetoothMac) { readQRCode.close(); tfAddress.setText(result); if (amount > 0) { tfAmt.setText(UnitUtil.formatValue(amount, UnitUtil.BitcoinUnit.BTC)); currentPassword.requestFocus(); } else { tfAmt.requestFocus(); } validateValues(); } @Override protected void error(final String messageResId, final Object... messageArgs) { readQRCode.reTry(LocaliserUtils.getString("scan_watch_only_address_error")); } }.parse(); } }); qrCodePanel.showPanel(); } }); return button; } private JPanel getenterPasswordMaV() { JPanel panel = Panels.newPanel( new MigLayout( Panels.migXLayout(), // Layout "[][][][]", // Columns "[]" // Rows )); // Keep track of the credentials fields currentPassword = TextBoxes.newPassword(); // Provide an invisible tar pit spinner spinner = Labels.newSpinner(Themes.currentTheme.fadedText(), BitherUI.NORMAL_PLUS_ICON_SIZE); spinner.setVisible(false); // Bind a document listener to allow instant update of UI to matched passwords currentPassword.getDocument().addDocumentListener( new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { updateModel(); } @Override public void removeUpdate(DocumentEvent e) { updateModel(); } @Override public void changedUpdate(DocumentEvent e) { updateModel(); } /** * Trigger any UI updates */ private void updateModel() { // Reset the credentials background validateValues(); currentPassword.setBackground(Themes.currentTheme.dataEntryBackground()); } }); panel.add(Labels.newEnterPassword(), "push,shrink"); panel.add(currentPassword, "growx,h 32,push"); //panel.add(showButton, "shrink"); // Ensure the icon label is a size suitable for rotation panel.add(spinner, BitherUI.NORMAL_PLUS_ICON_SIZE_MIG + ",wrap"); return panel; } private void validateValues() { boolean isValidAmounts = false; String amtString = tfAmt.getText().trim(); if (Utils.isNubmer(amtString)) { long btc = GenericUtils.toNanoCoins(amtString, 0).longValue(); if (btc > 0) { isValidAmounts = true; } else { } } boolean isValidAddress = Utils.validBicoinAddress(tfAddress.getText().trim()); SecureCharSequence password = new SecureCharSequence(currentPassword.getPassword()); boolean isValidPassword = Utils.validPassword(password) && password.length() >= BitherSetting.PASSWORD_LENGTH_MIN && password.length() <= BitherSetting.PASSWORD_LENGTH_MAX; password.wipe(); setOkEnabled(isValidAddress && isValidAmounts && isValidPassword); } @Override public void selectAddress(Address address) { changeAddress = address.getAddress(); } }