package com.dgex.offspring.ui.controls; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import nxt.Transaction; import nxt.TransactionType; import nxt.util.Convert; import org.apache.log4j.Logger; import org.eclipse.e4.ui.di.UISynchronize; import org.eclipse.e4.ui.services.IStylingEngine; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import com.dgex.offspring.config.Colors; import com.dgex.offspring.config.CompareMe; import com.dgex.offspring.config.IContact; import com.dgex.offspring.config.IContactsService; import com.dgex.offspring.config.Images; import com.dgex.offspring.messages.Messages; import com.dgex.offspring.nxtCore.core.TransactionDB; import com.dgex.offspring.nxtCore.core.TransactionHelper; import com.dgex.offspring.nxtCore.service.INxtService; import com.dgex.offspring.nxtCore.service.ITransaction; import com.dgex.offspring.swt.table.GenerericTableViewer; import com.dgex.offspring.swt.table.GenericComparator; import com.dgex.offspring.swt.table.GenericTableColumnBuilder; import com.dgex.offspring.swt.table.ICellActivateHandler; import com.dgex.offspring.swt.table.ICellDataProvider; import com.dgex.offspring.swt.table.IGenericTable; import com.dgex.offspring.swt.table.IGenericTableColumn; import com.dgex.offspring.swt.table.IPageableStructeredContentProvider; import com.dgex.offspring.swt.table.Pageable; import com.dgex.offspring.ui.InspectAccountDialog; import com.dgex.offspring.ui.InspectTransactionDialog; import com.dgex.offspring.user.service.IUserService; public class TransactionsViewer extends GenerericTableViewer { static Logger logger = Logger.getLogger(TransactionsViewer.class); static final RGB DARK_GREEN = new RGB(4, 15, 12); static final RGB DARK_RED = new RGB(139, 0, 19); static final String EMPTY_STRING = ""; static final Image MONEY_RECEIVED = Images.getImage("money_add.png"); static final Image MONEY_SEND = Images.getImage("money_delete.png"); static final Image MONEY = Images.getImage("money.png"); final IGenericTableColumn columnType = new GenericTableColumnBuilder("") .align(SWT.CENTER).textExtent("XXX").editable(false) .provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { // OK ITransaction transaction = (ITransaction) element; Transaction t = transaction.getNative(); if (accountId.equals(t.getSenderId())) { if (accountId.equals(t.getRecipientId())) { return MONEY; } return MONEY_SEND; } else if (accountId.equals(t.getRecipientId())) { return MONEY_RECEIVED; } return null; } @Override public void getCellData(Object element, Object[] data) { data[IMAGE] = getCellValue(element); data[TEXT] = EMPTY_STRING; } @Override public int compare(Object v1, Object v2) { return 0; } }).build(); final IGenericTableColumn columnAmount = new GenericTableColumnBuilder( Messages.TransactionTable_column_amount_label).align(SWT.RIGHT) .textExtent("1000000000").provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { // NOT OK ITransaction t = (ITransaction) element; long received = t.getAmountReceived(accountId); long spend = t.getAmountSpend(accountId); return Long.valueOf(received - spend); } @Override public void getCellData(Object element, Object[] data) { Long amount = (Long) getCellValue(element); data[FONT] = JFaceResources.getFontRegistry().getBold(""); data[TEXT] = Long.toString(amount); if (amount > 0) data[FOREGROUND] = Colors.getColor(DARK_GREEN); else if (amount < 0) data[FOREGROUND] = Colors.getColor(DARK_RED); else data[FOREGROUND] = null; } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((Long) v1, (Long) v2); } }).build(); final IGenericTableColumn columnBalance = new GenericTableColumnBuilder( Messages.TransactionTable_column_balance_label).align(SWT.RIGHT) .textExtent("1000000000").provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { // NOT OK ITransaction t = (ITransaction) element; return Long.valueOf(t.getRunningTotal()); // Long } @Override public void getCellData(Object element, Object[] data) { Long balance = (Long) getCellValue(element); if (balance < 0l) data[TEXT] = EMPTY_STRING; else data[TEXT] = Long.toString(balance); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((Long) v1, (Long) v2); } }).build(); final IGenericTableColumn columnConfirmations = new GenericTableColumnBuilder( "").align(SWT.CENTER).textExtent("1000000") .provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { ITransaction t = (ITransaction) element; return Integer.valueOf(t.getNumberOfConfirmations()); } @Override public void getCellData(Object element, Object[] data) { Integer confirmations = (Integer) getCellValue(element); data[TEXT] = confirmations > 10 ? "10+" : Integer .toString(confirmations); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((Integer) v1, (Integer) v2); } }).build(); final IGenericTableColumn columnTransactionType = new GenericTableColumnBuilder( "type").align(SWT.LEFT).textExtent("xxxxxxxx") .provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { ITransaction transaction = (ITransaction) element; Transaction t = transaction.getNative(); return TransactionTypes.getTransactionType(t); } @Override public void getCellData(Object element, Object[] data) { data[TEXT] = getCellValue(element); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((String) v1, (String) v2); } }).build(); final IGenericTableColumn columnDate = new GenericTableColumnBuilder( Messages.TransactionTable_column_date_label).align(SWT.LEFT) .textExtent("dd MMM yy hh:mm:ss ").provider(new ICellDataProvider() { private final SimpleDateFormat dateFormat = new SimpleDateFormat( "dd MMM yy H:mm:ss"); @Override public Object getCellValue(Object element) { ITransaction t = (ITransaction) element; return t.getTimestamp(); // Date } @Override public void getCellData(Object element, Object[] data) { data[TEXT] = dateFormat.format(getCellValue(element)); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare(((Date) v1).getTime(), ((Date) v2).getTime()); } }).build(); final IGenericTableColumn columnAccount = new GenericTableColumnBuilder( Messages.TransactionTable_column_account_label).align(SWT.LEFT) .textExtent("12345678901234567890123") .activate(new ICellActivateHandler() { @Override public void activate(Object element) { ITransaction transaction = (ITransaction) element; Transaction t = transaction.getNative(); Long id = null; if (accountId.equals(t.getSenderId())) { id = t.getRecipientId(); } else { id = t.getSenderId(); } if (id != null) { InspectAccountDialog.show(id, nxt, engine, userService, sync, contactsService); } } }).provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { ITransaction transaction = (ITransaction) element; Transaction t = transaction.getNative(); if (accountId.equals(t.getSenderId())) { return Convert.toUnsignedLong(t.getRecipientId()); } return Convert.toUnsignedLong(t.getSenderId()); } @Override public void getCellData(Object element, Object[] data) { data[TEXT] = getCellValue(element); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((String) v1, (String) v2); } }).build(); final IGenericTableColumn columnName = new GenericTableColumnBuilder( Messages.TransactionTable_column_name_label).align(SWT.LEFT) .textExtent("12345678901234567890123").provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { ITransaction transaction = (ITransaction) element; Transaction t = transaction.getNative(); IContact contact; if (t.getSenderId().equals(accountId)) contact = getContactsService().getContact( Convert.toUnsignedLong(t.getRecipientId())); else contact = getContactsService().getContact( Convert.toUnsignedLong(t.getSenderId())); if (contact != null) return contact.getName(); return EMPTY_STRING; } @Override public void getCellData(Object element, Object[] data) { data[TEXT] = getCellValue(element); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((String) v1, (String) v2); } }).build(); final IGenericTableColumn columnFee = new GenericTableColumnBuilder( Messages.TransactionTable_column_fee_label).align(SWT.RIGHT) .textExtent("1000000").provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { ITransaction t = (ITransaction) element; return Integer.valueOf(t.getFee()); } @Override public void getCellData(Object element, Object[] data) { data[TEXT] = Integer.toString((Integer) getCellValue(element)); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((Integer) v1, (Integer) v2); } }).build(); final IGenericTableColumn columnID = new GenericTableColumnBuilder( Messages.TransactionTable_column_transaction_label).align(SWT.LEFT) .textExtent("12345678901234567890123") .activate(new ICellActivateHandler() { @Override public void activate(Object element) { ITransaction transaction = (ITransaction) element; Transaction t = transaction.getNative(); Long id = t.getId(); if (id != null) { InspectTransactionDialog.show(id, nxt, engine, userService, sync, contactsService); } } }).provider(new ICellDataProvider() { @Override public Object getCellValue(Object element) { ITransaction t = (ITransaction) element; return t.getStringId(); } @Override public void getCellData(Object element, Object[] data) { data[TEXT] = getCellValue(element); } @Override public int compare(Object v1, Object v2) { return CompareMe.compare((String) v1, (String) v2); } }).build(); final IPageableStructeredContentProvider contentProvider = new IPageableStructeredContentProvider() { private Long accountId = null; private int currentPage = 1; private int pageSize = -1; private TransactionDB.LazyList list; @Override public void dispose() { if (list != null) { list.dispose(); list = null; } } @Override public void reset(Viewer viewer) { if (list != null) list.dispose(); if (pageSize < 1) throw new RuntimeException("Illegal page size"); if (accountId == null) return; int timestamp = 0; Boolean orderAscending = Boolean.FALSE; Object referencedTransaction = null; TransactionType[] recipientTypes = { TransactionType.Payment.ORDINARY, }; TransactionType[] senderTypes = { TransactionType.Payment.ORDINARY, TransactionType.Messaging.ALIAS_ASSIGNMENT, TransactionType.Messaging.ARBITRARY_MESSAGE, TransactionType.Messaging.POLL_CREATION, TransactionType.Messaging.VOTE_CASTING, TransactionType.ColoredCoins.ASK_ORDER_CANCELLATION, TransactionType.ColoredCoins.ASK_ORDER_PLACEMENT, TransactionType.ColoredCoins.ASSET_ISSUANCE, TransactionType.ColoredCoins.BID_ORDER_CANCELLATION, TransactionType.ColoredCoins.BID_ORDER_PLACEMENT }; this.list = TransactionDB.getTransactions(accountId, recipientTypes, senderTypes, timestamp, orderAscending, referencedTransaction, ((TransactionsViewer) viewer).nxt); this.currentPage = 1; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { this.accountId = (Long) newInput; } @Override public Object[] getElements(Object inputElement) { if (accountId == null || list == null) { return new Object[0]; } logger.info("getElements page=" + currentPage + " size=" + pageSize); list.ensureCapacity(currentPage * pageSize + 1); Pageable<ITransaction> pageable = new Pageable<ITransaction>( list.getList(), pageSize); pageable.setPage(currentPage); List<ITransaction> transactions = pageable.getListForPage(); /* Add all pending transactions for this account */ if (currentPage == 1) { List<Transaction> pending = new ArrayList<Transaction>(); for (Transaction t : nxt.getPendingTransactions()) { if (accountId.equals(t.getSenderId()) || accountId.equals(t.getRecipientId())) { pending.add(t); } } if (pending.size() > 0) { List<Transaction> remove = new ArrayList<Transaction>(); for (Transaction t : pending) { for (ITransaction it : transactions) { if (t.getId().equals(it.getNative().getId())) { remove.add(t); break; } } } for (Transaction t : remove) { nxt.getPendingTransactions().remove(t); pending.remove(t); } for (Transaction t : pending) { transactions.add(0, new TransactionHelper(nxt, t)); } } } logger.info("getElements returns ELEMENTS.size=" + transactions.size()); return transactions.toArray(new Object[transactions.size()]); } @Override public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } @Override public void setPageSize(int pageSize) { this.pageSize = pageSize; } @Override public int getElementCount() { return list == null ? 0 : list.available(); } }; private IContactsService contactsService; private Long accountId; public INxtService nxt; private IStylingEngine engine; private IUserService userService; private UISynchronize sync; public TransactionsViewer(Composite parent, Long accountId, IContactsService contactsService, INxtService nxt, IStylingEngine engine, IUserService userService, UISynchronize sync) { super(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.BORDER); this.contactsService = contactsService; this.nxt = nxt; this.accountId = accountId; this.engine = engine; this.userService = userService; this.sync = sync; setGenericTable(new IGenericTable() { @Override public int getDefaultSortDirection() { return GenericComparator.DESCENDING; } @Override public IGenericTableColumn getDefaultSortColumn() { return columnDate; } @Override public IStructuredContentProvider getContentProvider() { return contentProvider; } @Override public IGenericTableColumn[] getColumns() { return new IGenericTableColumn[] { columnType, columnConfirmations, columnDate, columnAmount, columnFee, columnAccount, columnID, columnTransactionType }; } }); setInput(accountId); } public Long getAccountId() { return accountId; } public IContactsService getContactsService() { return contactsService; } }