package com.dgex.offspring.ui; import java.text.DecimalFormat; import nxt.Asset; import nxt.Constants; import nxt.NxtException.ValidationException; import nxt.Transaction; import nxt.util.Convert; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import com.dgex.offspring.nxtCore.service.IAccount; import com.dgex.offspring.nxtCore.service.INxtService; import com.dgex.offspring.nxtCore.service.TransactionException; import com.dgex.offspring.swt.wizard.GenericTransactionWizard; import com.dgex.offspring.swt.wizard.IGenericTransaction; import com.dgex.offspring.swt.wizard.IGenericTransactionField; import com.dgex.offspring.user.service.IUserService; public class PlaceBidOrderWizard extends GenericTransactionWizard { static String THIRD_COLUMN = "000000000000"; final IGenericTransactionField fieldAsset = new IGenericTransactionField() { private Text textAsset; private Text textAssetReadonly; public Label labelAssetName; private Label labelAssetNameReadonly; static final String EMPTY_NAME = " "; // 15 characters @Override public String getLabel() { return "Asset"; } @Override public Object getValue() { String id_as_string = textAsset.getText().trim(); Long id = id_as_string.isEmpty() ? null : Convert .parseUnsignedLong(id_as_string); if (id != null) { return Asset.getAsset(id); } return null; } @Override public Control createControl(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0) .margins(0, 0).applyTo(composite); textAsset = new Text(composite, SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).applyTo(textAsset); String id = presetAssetId != null ? Convert.toUnsignedLong(presetAssetId) : ""; textAsset.setText(id); textAsset.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { requestVerification(); } }); labelAssetName = new Label(composite, SWT.NONE); GC gc = new GC(labelAssetName); GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER) .hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT) .applyTo(labelAssetName); gc.dispose(); labelAssetName.setText(EMPTY_NAME); return composite; } @Override public Control createReadonlyControl(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0) .margins(0, 0).applyTo(composite); textAssetReadonly = new Text(composite, SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).applyTo(textAssetReadonly); textAssetReadonly.setText(""); textAssetReadonly.setEditable(false); labelAssetNameReadonly = new Label(composite, SWT.NONE); GC gc = new GC(labelAssetNameReadonly); GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER) .hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT) .applyTo(labelAssetNameReadonly); gc.dispose(); labelAssetNameReadonly.setText(""); return composite; } @Override public boolean verify(String[] message) { String id_as_string = textAsset.getText().trim(); Long id = id_as_string.isEmpty() ? null : Convert .parseUnsignedLong(id_as_string); if (id == null) { labelAssetName.setText(EMPTY_NAME); message[0] = "Invalid id"; return false; } Asset asset = Asset.getAsset(id); if (asset == null) { labelAssetName.setText(EMPTY_NAME); message[0] = "Asset does not exist"; return false; } labelAssetName.setText(asset.getName()); textAssetReadonly.setText(id_as_string); labelAssetNameReadonly.setText(asset.getName()); return true; } }; final IGenericTransactionField fieldQuantity = new IGenericTransactionField() { private Text textQuantity; private Text textQuantityReadonly; @Override public String getLabel() { return "Quantity"; } @Override public Object getValue() { try { return Integer.parseInt(textQuantity.getText().trim()); } catch (NumberFormatException e) { return -1; } }; @Override public Control createControl(Composite parent) { textQuantity = new Text(parent, SWT.BORDER); textQuantity.setText(Integer.toString(presetQuantity)); textQuantity.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { requestVerification(); } }); return textQuantity; } @Override public Control createReadonlyControl(Composite parent) { textQuantityReadonly = new Text(parent, SWT.BORDER); textQuantityReadonly.setEditable(false); return textQuantityReadonly; } @Override public boolean verify(String[] message) { String text = textQuantity.getText().trim(); int quantity; try { quantity = Integer.parseInt(text); } catch (NumberFormatException nfe) { message[0] = "Value must be numeric"; return false; } if (quantity < 1) { message[0] = "Value must be greater than 1"; return false; } Asset asset = (Asset) fieldAsset.getValue(); if (asset != null) { if (quantity > asset.getQuantity()) { message[0] = "There where only " + asset.getQuantity() + " assets issued"; return false; } } textQuantityReadonly.setText(text); return true; } }; /* Price is expressed in NXT sends! User enters price in NXT with precision */ final IGenericTransactionField fieldPrice = new IGenericTransactionField() { private Text textPrice; private Text textPriceReadonly; private Label labelPriceTotal; private Label labelPriceTotalReadonly; private final DecimalFormat formatDouble = new DecimalFormat("#.##"); private boolean ignore = false; private final ModifyListener modificationListener = new ModifyListener() { @Override public void modifyText(ModifyEvent e) { ignore = true; requestVerification(); ignore = false; } }; @Override public String getLabel() { return "Price"; } @Override public Object getValue() { try { double p = Double.parseDouble(textPrice.getText().trim()); p = (double) Math.round(p * 100) / 100; // round to two decimals return (long) (p * 100); // price in cents } catch (NumberFormatException e) { return (long) -1; } }; @Override public Control createControl(Composite parent) { String price; if (presetAssetId != null && presetPrice > 0) { Double p = new Long(presetPrice).doubleValue() / 100; p = (double) Math.round(p * 100) / 100; price = Double.toString(p); } else { price = "0.00"; } Composite composite = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0) .margins(0, 0).applyTo(composite); textPrice = new Text(composite, SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).applyTo(textPrice); textPrice.setText(price); textPrice.addModifyListener(modificationListener); labelPriceTotal = new Label(composite, SWT.NONE); GC gc = new GC(labelPriceTotal); GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER) .hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT) .applyTo(labelPriceTotal); gc.dispose(); labelPriceTotal.setText("0.0"); return composite; // ------------------ // textPrice = new Text(parent, SWT.BORDER); // // if (presetAssetId != null && presetPrice > 0) { // Double p = new Long(presetPrice).doubleValue() / 100; // p = (double) Math.round(p * 100) / 100; // textPrice.setText(Double.toString(p)); // } // else { // textPrice.setText("0"); // } // // textPrice.addModifyListener(modificationListener); // return textPrice; } @Override public Control createReadonlyControl(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0) .margins(0, 0).applyTo(composite); textPriceReadonly = new Text(composite, SWT.BORDER); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER) .grab(true, false).applyTo(textPriceReadonly); textPriceReadonly.setText(""); labelPriceTotalReadonly = new Label(composite, SWT.NONE); GC gc = new GC(labelPriceTotalReadonly); GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER) .hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT) .applyTo(labelPriceTotalReadonly); gc.dispose(); labelPriceTotalReadonly.setText("0.0"); return composite; // textPriceReadonly = new Text(parent, SWT.BORDER); // textPriceReadonly.setEditable(false); // return textPriceReadonly; } @Override public boolean verify(String[] message) { labelPriceTotalReadonly.setText(""); labelPriceTotal.setText(""); String text = textPrice.getText().trim(); long priceInCents; // in NXT cents try { Double p = Double.parseDouble(text); // round the double to two places after comma p = (double) Math.round(p * 100) / 100; // correct the user input to remove the to high precision if (ignore == false) { textPrice.removeModifyListener(modificationListener); textPrice.setText(Double.toString(p)); textPrice.addModifyListener(modificationListener); } priceInCents = (long) (p * 100); } catch (NumberFormatException e) { message[0] = "Value must be numeric"; return false; } if (priceInCents < 1) { message[0] = "Value must be greater than 0.01"; return false; } if (priceInCents > Constants.MAX_BALANCE * 100L) { message[0] = "Value must be less than " + Constants.MAX_BALANCE; return false; } /* calculate the total */ int quantity = (int) fieldQuantity.getValue(); if (quantity > 0) { Double price = (double) (priceInCents * quantity); // price in cents price = price / 100L; String txt = Constants.MAX_BALANCE >= price ? formatDouble .format(price) : "MAX"; labelPriceTotalReadonly.setText(txt); labelPriceTotal.setText(txt); } textPriceReadonly.setText(text); return true; } }; // final IGenericTransactionField fieldTotal = new IGenericTransactionField() // { // // private Label labelTotal; // private Label labelTotalReadonly; // // @Override // public String getLabel() { // return "Total"; // } // // @Override // public Object getValue() { // return null; // } // // @Override // public Control createControl(Composite parent) { // labelTotal = new Label(parent, SWT.NONE); // if (presetAssetId != null && presetPrice > 0) { // Double p = new Long(presetPrice).doubleValue() / 100; // p = p * presetQuantity; // p = (double) Math.round(p * 100) / 100; // labelTotal.setText(Double.toString(p)); // } // else { // labelTotal.setText("0"); // } // return labelTotal; // } // // @Override // public Control createReadonlyControl(Composite parent) { // labelTotalReadonly = new Label(parent, SWT.NONE); // labelTotalReadonly.setText(labelTotal.getText()); // return labelTotalReadonly; // } // // @Override // public boolean verify(String[] message) { // long price = (long) fieldPrice.getValue(); // price in cents // int quantity = (int) fieldQuantity.getValue(); // String text = ""; // if (price != -1 && quantity != -1) { // Double p = new Long(price).doubleValue() / 100; // p = p * presetQuantity; // p = (double) Math.round(p * 100) / 100; // text = Double.toString(p); // } // labelTotal.setText(text); // labelTotalReadonly.setText(text); // return true; // } // // }; private Long presetAssetId; private int presetQuantity; private long presetPrice; // in cents per asset public PlaceBidOrderWizard(final IUserService userService, final INxtService nxt, Long assetId, int quantity, long price) { super(userService); this.presetAssetId = assetId; this.presetQuantity = quantity; this.presetPrice = price; setWindowTitle("Place Buy Order"); setTransaction(new IGenericTransaction() { @Override public String sendTransaction(String[] message) { IAccount sender = user.getAccount(); Asset asset = (Asset) fieldAsset.getValue(); int quantity = (int) fieldQuantity.getValue(); long price = (long) fieldPrice.getValue(); // price is in cents PromptFeeDeadline dialog = new PromptFeeDeadline(getShell()); dialog.setMinimumFee(1); dialog.setFee(1); if (dialog.open() != Window.OK) { message[0] = "Invalid fee and deadline"; return null; } int fee = dialog.getFee(); short deadline = dialog.getDeadline(); try { Transaction t = nxt.createPlaceBidOrderTransaction(sender, asset.getId(), quantity, price, deadline, fee, null); return t.getStringId(); } catch (ValidationException e) { message[0] = e.getMessage(); } catch (TransactionException e) { message[0] = e.getMessage(); } return null; } @Override public IGenericTransactionField[] getFields() { return new IGenericTransactionField[] { fieldSender, fieldAsset, fieldQuantity, fieldPrice /* , fieldTotal */}; } @Override public boolean verifySender(String message[]) { if (user == null) { message[0] = "Invalid sender"; return false; } if (user.getAccount().isReadOnly()) { message[0] = "This is a readonly account"; return false; } int quantity = (int) fieldQuantity.getValue(); long price = (long) fieldPrice.getValue(); if (quantity != -1 && price != -1) { long totalPriceInCents = quantity * price; long totalPrice = (totalPriceInCents / 100L) + 1; if (totalPrice > user.getAccount().getBalance()) { message[0] = "Insufficient balance"; return false; } } return true; } }); } }