/** * Copyright 2011 multibit.org * * Licensed under the MIT license (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://opensource.org/licenses/mit-license.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.multibit.viewsystem.swing.view.dialogs; import com.google.bitcoin.core.Transaction; import com.google.bitcoin.core.Wallet.BalanceType; import com.google.bitcoin.core.Wallet.SendRequest; import org.multibit.controller.Controller; import org.multibit.controller.bitcoin.BitcoinController; import org.multibit.exchange.CurrencyConverter; import org.multibit.model.bitcoin.BitcoinModel; import org.multibit.utils.ImageLoader; import org.multibit.viewsystem.swing.ColorAndFontConstants; import org.multibit.viewsystem.swing.MultiBitFrame; import org.multibit.viewsystem.swing.action.HelpContextAction; import org.multibit.viewsystem.swing.action.OkBackToParentAction; import org.multibit.viewsystem.swing.view.components.*; import org.multibit.viewsystem.swing.view.panels.HelpContentsPanel; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * The validation error dialog - used to tell the user their input is invalid. */ public class ValidationErrorDialog extends MultiBitDialog { private static final long serialVersionUID = 191499812345057705L; private static final int HEIGHT_DELTA = 150; private static final int WIDTH_DELTA = 160; private final Controller controller; private final BitcoinController bitcoinController; private final SendRequest sendRequest; private boolean insufficientFee; /** * Creates a new {@link ValidationErrorDialog}. */ public ValidationErrorDialog(BitcoinController bitcoinController, MultiBitFrame mainFrame, SendRequest sendRequest, boolean insufficientFee) { super(mainFrame, bitcoinController.getLocaliser().getString("validationErrorView.title")); this.bitcoinController = bitcoinController; this.controller = this.bitcoinController; this.sendRequest = sendRequest; this.insufficientFee = insufficientFee; initUI(); } /** * Initialise the validation error dialog. */ private void initUI() { // Get the data out of the user preferences. String addressValue = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.VALIDATION_ADDRESS_VALUE); String amountValue = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.VALIDATION_AMOUNT_VALUE); String amountPlusConversionToFiat = CurrencyConverter.INSTANCE.prettyPrint(amountValue); // Invalid address. String addressIsInvalid = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.VALIDATION_ADDRESS_IS_INVALID); boolean addressIsInvalidBoolean = false; if (Boolean.TRUE.toString().equals(addressIsInvalid)) { addressIsInvalidBoolean = true; } // Amount is missing. String amountIsMissing = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.VALIDATION_AMOUNT_IS_MISSING); boolean amountIsMissingBoolean = false; if (Boolean.TRUE.toString().equals(amountIsMissing)) { amountIsMissingBoolean = true; } // Invalid amount i.e. not a number or could not parse. String amountIsInvalid = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.VALIDATION_AMOUNT_IS_INVALID); boolean amountIsInvalidBoolean = false; if (Boolean.TRUE.toString().equals(amountIsInvalid)) { amountIsInvalidBoolean = true; } // Amount is negative or zero. String amountIsNegativeOrZero = this.bitcoinController.getModel().getActiveWalletPreference( BitcoinModel.VALIDATION_AMOUNT_IS_NEGATIVE_OR_ZERO); boolean amountIsNegativeOrZeroBoolean = false; if (Boolean.TRUE.toString().equals(amountIsNegativeOrZero)) { amountIsNegativeOrZeroBoolean = true; } // Amount is too small. String amountIsTooSmall = this.bitcoinController.getModel().getActiveWalletPreference( BitcoinModel.VALIDATION_AMOUNT_IS_TOO_SMALL); boolean amountIsTooSmallBoolean = false; if (Boolean.TRUE.toString().equals(amountIsTooSmall)) { amountIsTooSmallBoolean = true; } // Amount is more than available funds. String notEnoughFunds = this.bitcoinController.getModel().getActiveWalletPreference(BitcoinModel.VALIDATION_NOT_ENOUGH_FUNDS); boolean notEnoughFundsBoolean = false; if (Boolean.TRUE.toString().equals(notEnoughFunds) || insufficientFee) { notEnoughFundsBoolean = true; } // Get localised validation messages. StringBuilder completeMessage = new StringBuilder(); int rows = 0; String longestRow = ""; if (addressIsInvalidBoolean) { completeMessage.append(controller.getLocaliser().getString("validationErrorView.addressInvalidMessage", new String[] { addressValue })); longestRow = completeMessage.toString(); rows++; } if (amountIsMissingBoolean) { if (completeMessage.length()>0) { completeMessage.append("\n"); } String textToAdd = controller.getLocaliser().getString("validationErrorView.amountIsMissingMessage"); if (textToAdd.length() > longestRow.length()) { longestRow = textToAdd; } completeMessage.append(textToAdd); rows++; } if (amountIsInvalidBoolean) { if (completeMessage.length() > 0) { completeMessage.append("\n"); } String textToAdd = controller.getLocaliser().getString("validationErrorView.amountInvalidMessage", new String[] { amountValue }); if (textToAdd.length() > longestRow.length()) { longestRow = textToAdd; } completeMessage.append(textToAdd); rows++; } if (amountIsNegativeOrZeroBoolean) { if (completeMessage.length()>0) { completeMessage.append("\n"); } String textToAdd = controller.getLocaliser().getString("validationErrorView.amountIsNegativeOrZeroMessage"); if (textToAdd.length() > longestRow.length()) { longestRow = textToAdd; } completeMessage.append(textToAdd); rows++; } if (amountIsTooSmallBoolean) { if (completeMessage.length()>0) { completeMessage.append("\n"); } String textToAdd = controller.getLocaliser().getString("validationErrorView.amountIsTooSmallMessage", new String[]{Transaction.MIN_NONDUST_OUTPUT.toString()}); if (textToAdd.length() > longestRow.length()) { longestRow = textToAdd; } completeMessage.append(textToAdd); rows++; } if (notEnoughFundsBoolean) { if (completeMessage.length()>0) { completeMessage.append("\n"); } String textToAdd = controller.getLocaliser().getString("validationErrorView.notEnoughFundsMessage", new String[] { amountPlusConversionToFiat}); if (this.bitcoinController.getModel().getActiveWallet().getBalance(BalanceType.AVAILABLE).compareTo(this.bitcoinController.getModel().getActiveWallet().getBalance(BalanceType.ESTIMATED)) != 0) { textToAdd = controller.getLocaliser().getString("validationErrorView.notEnoughFundsMessage2", new String[] { amountPlusConversionToFiat}); } // There is an extra "BTC." in the translations - remove and add a return. textToAdd = textToAdd.replaceAll("BTC\\.", "\\."); String[] lines = textToAdd.split("\\n"); for (int i = 0; i < lines.length; i++) { if (lines[i] != null && lines[i].length() > longestRow.length()) { longestRow = lines[i]; } if (lines[i] != null && lines[i].length() > 0) { if (i == 0) { completeMessage.append(lines[i]); } else { completeMessage.append("\n").append(lines[i]); } rows++; } } } // Spacer row at top and bottom. rows = rows + 2; // Tell user validation messages. Action availableToSpendHelpAction = new HelpContextAction(controller, null, "validationErrorView.moreHelp", "multiBitFrame.helpMenuTooltip", "multiBitFrame.helpMenuText", HelpContentsPanel.HELP_AVAILABLE_TO_SPEND_URL); HelpButton availableToSpendHelpButton = new HelpButton(availableToSpendHelpAction, controller, true); final ValidationErrorDialog finalValidationErrorDialog = this; availableToSpendHelpButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { finalValidationErrorDialog.setVisible(false); }}); OkBackToParentAction okAction = new OkBackToParentAction(controller, this); MultiBitButton okButton = new MultiBitButton(okAction, controller); okButton.setOpaque(true); okButton.setBackground(ColorAndFontConstants.BACKGROUND_COLOR); Object[] options = {okButton}; if (this.bitcoinController.getModel().getActiveWallet().getBalance(BalanceType.AVAILABLE).compareTo(this.bitcoinController.getModel().getActiveWallet().getBalance(BalanceType.ESTIMATED)) != 0) { options = new Object[] { okButton, availableToSpendHelpButton}; } MultiBitTextArea completeMessageTextArea = new MultiBitTextArea("\n" + completeMessage.toString() + "\n", rows, 20, controller); completeMessageTextArea.setOpaque(false); completeMessageTextArea.setBackground(ColorAndFontConstants.BACKGROUND_COLOR); completeMessageTextArea.setEditable(false); completeMessageTextArea.setFont(FontSizer.INSTANCE.getAdjustedDefaultFont()); completeMessageTextArea.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8)); JOptionPane optionPane = new JOptionPane(completeMessageTextArea, JOptionPane.ERROR_MESSAGE, JOptionPane.DEFAULT_OPTION, ImageLoader.createImageIcon(ImageLoader.EXCLAMATION_MARK_ICON_FILE), options, options[0]); add(optionPane); optionPane.setBackground(ColorAndFontConstants.BACKGROUND_COLOR); optionPane.setOpaque(true); FontMetrics fontMetrics = optionPane.getFontMetrics(FontSizer.INSTANCE.getAdjustedDefaultFont()); int minimumHeight = fontMetrics.getHeight() * rows + HEIGHT_DELTA; //log.debug("longest row = '" + longestRow + "'"); int minimumWidth = fontMetrics.stringWidth(longestRow) + WIDTH_DELTA; setMinimumSize(new Dimension(minimumWidth, minimumHeight)); positionDialogRelativeToParent(this, 0.5D, 0.47D); } }