net.sf.jmoney.stocks.pages.StockBalancesEditor.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jmoney.stocks.pages.StockBalancesEditor.java

Source

/*
 *
 *  JMoney - A Personal Finance Manager
 *  Copyright (c) 2009 Nigel Westbury <westbury@users.sourceforge.net>
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

package net.sf.jmoney.stocks.pages;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import net.sf.jmoney.JMoneyPlugin;
import net.sf.jmoney.fields.DateControl;
import net.sf.jmoney.model2.DatastoreManager;
import net.sf.jmoney.model2.Entry;
import net.sf.jmoney.model2.EntryInfo;
import net.sf.jmoney.model2.ExtendableObject;
import net.sf.jmoney.model2.ListPropertyAccessor;
import net.sf.jmoney.model2.ScalarPropertyAccessor;
import net.sf.jmoney.model2.SessionChangeAdapter;
import net.sf.jmoney.stocks.ShowStockDetailsHandler;
import net.sf.jmoney.stocks.model.Stock;
import net.sf.jmoney.stocks.model.StockAccount;
import net.sf.jmoney.stocks.model.StockEntry;
import net.sf.jmoney.stocks.model.StockEntryInfo;
import net.sf.jmoney.views.AccountEditor;
import net.sf.jmoney.views.AccountEditorInput;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.EditorPart;

public class StockBalancesEditor extends EditorPart {
    static public final String ID = "net.sf.jmoney.stocks.stockBalancesEditor";

    private AccountEditor accountEditor;

    /**
     * The account being shown in this page.
     */
    private StockAccount account;

    private class StockWrapper {
        private Stock stock;
        public long total = 0;

        public StockWrapper(Stock stock) {
            this.stock = stock;
        }

    }

    private Map<Stock, StockWrapper> totals;

    private TableViewer balancesViewer;

    private Button zeroBalanceCheckbox;

    private DateControl balanceDateControl;

    private SessionChangeAdapter sessionListener = new SessionChangeAdapter() {
        @Override
        public void objectChanged(ExtendableObject changedObject, ScalarPropertyAccessor changedProperty,
                Object oldValue, Object newValue) {
            if (changedObject instanceof Entry) {
                Entry changedEntry = (Entry) changedObject;
                if (changedEntry.getAccount() == account && changedEntry.getCommodityInternal() instanceof Stock
                        && changedProperty == EntryInfo.getAmountAccessor()) {

                }
            }

        }

        @Override
        public void objectCreated(ExtendableObject newObject) {
            // TODO Auto-generated method stub

        }

        @Override
        public void objectDestroyed(ExtendableObject deletedObject) {
            // TODO Auto-generated method stub

        }

        @Override
        public void objectInserted(ExtendableObject newObject) {
            // TODO Auto-generated method stub
            System.out.println("here");
        }

        @Override
        public void objectMoved(ExtendableObject movedObject, ExtendableObject originalParent,
                ExtendableObject newParent, ListPropertyAccessor originalParentListProperty,
                ListPropertyAccessor newParentListProperty) {
            // TODO Auto-generated method stub

        }

        @Override
        public void objectRemoved(ExtendableObject deletedObject) {
            // TODO Auto-generated method stub

        }

        @Override
        public void performRefresh() {
            // TODO Auto-generated method stub
            calculateTotals();
        }
    };

    /**
     * Currently this editor can be created only when given an AccountEditor.
     * This editor is a child editor of the AccountEditor (a multi-page editor),
     * though this class does not make that assumption.  The AccountEditor is used
     * for certain actions such as opening stock details pages.
     * 
     * @param editor
     */
    public StockBalancesEditor(AccountEditor accountEditor) {
        this.accountEditor = accountEditor;
    }

    @Override
    public void init(IEditorSite site, IEditorInput input) throws PartInitException {

        setSite(site);
        setInput(input);

        // Set the account that this page is viewing and editing.
        AccountEditorInput input2 = (AccountEditorInput) input;
        DatastoreManager sessionManager = (DatastoreManager) site.getPage().getInput();
        account = (StockAccount) sessionManager.getSession().getAccountByFullName(input2.getFullAccountName());

        sessionManager.addChangeListener(sessionListener);
    }

    @Override
    public void dispose() {
        DatastoreManager sessionManager = (DatastoreManager) getSite().getPage().getInput();
        sessionManager.removeChangeListener(sessionListener);
    }

    @Override
    public boolean isDirty() {
        // Page is never dirty
        return false;
    }

    @Override
    public boolean isSaveAsAllowed() {
        return false;
    }

    @Override
    public void doSave(IProgressMonitor monitor) {
        // Will never be called because editor is never dirty.
    }

    @Override
    public void doSaveAs() {
        // Will never be called because editor is never dirty and 'save as' is not allowed anyway.
    }

    @Override
    public void createPartControl(Composite parent) {
        FormToolkit toolkit = new FormToolkit(parent.getDisplay());
        ScrolledForm form = toolkit.createScrolledForm(parent);
        form.getBody().setLayout(new FillLayout());

        // Get the handler service and pass it on so that handlers can be activated as appropriate
        IHandlerService handlerService = (IHandlerService) getSite().getService(IHandlerService.class);

        Composite contents = createContents(form.getBody());

        final ViewerFilter hideZeroBalancesFilter = new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parentElement, Object element) {
                StockWrapper wrapper = (StockWrapper) element;
                return wrapper.total != 0;
            }
        };

        balanceDateControl.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                Date balanceDate = balanceDateControl.getDate();
                if (balanceDate != null) {
                    calculateTotals();
                }
            }
        });

        zeroBalanceCheckbox.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                if (zeroBalanceCheckbox.getSelection()) {
                    balancesViewer.removeFilter(hideZeroBalancesFilter);
                } else {
                    balancesViewer.addFilter(hideZeroBalancesFilter);
                }
            }
        });

        balanceDateControl.setDate(new Date());
        calculateTotals();

        // Activate the handlers
        //      IHandler handler = new NewTransactionHandler(rowTracker, fEntriesControl);
        //      handlerService.activateHandler("net.sf.jmoney.newTransaction", handler);      

        toolkit.paintBordersFor(contents);

        form.setText("Investment Account Balances");
    }

    private Composite createContents(Composite parent) {
        Composite composite = new Composite(parent, SWT.None);
        composite.setLayout(new GridLayout());

        createConfigurationControls(composite);

        Control table = createTable(composite);
        table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        return composite;
    }

    private void calculateTotals() {
        Date asOf = balanceDateControl.getDate();

        totals = new HashMap<Stock, StockWrapper>();

        for (Entry entry : account.getEntries()) {
            if (!entry.getTransaction().getDate().after(asOf)) {
                StockEntry entry2 = entry.getExtension(StockEntryInfo.getPropertySet(), false);
                if (entry2 != null && entry2.getCommodity() instanceof Stock) {
                    Stock stock = (Stock) entry2.getCommodity();
                    StockWrapper stockWrapper = totals.get(stock);
                    if (stockWrapper == null) {
                        stockWrapper = new StockWrapper(stock);
                        totals.put(stock, stockWrapper);
                    }

                    stockWrapper.total += entry.getAmount();
                }
            }
        }

        balancesViewer.setInput(totals.values());
    }

    private Control createConfigurationControls(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new GridLayout(5, false));

        createDateControl(composite);
        createShowZeroBalanceCheckbox(composite);

        return composite;
    }

    private Control createDateControl(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new GridLayout(5, false));

        new Label(composite, SWT.NONE).setText("Balance as of:");

        balanceDateControl = new DateControl(composite);

        return composite;
    }

    private Control createShowZeroBalanceCheckbox(Composite parent) {
        zeroBalanceCheckbox = new Button(parent, SWT.CHECK);
        zeroBalanceCheckbox.setText("Show Stock with Zero Balance");

        return zeroBalanceCheckbox;
    }

    private Control createTable(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new GridLayout());

        balancesViewer = new TableViewer(composite, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION);

        GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
        gridData.widthHint = 300;
        gridData.heightHint = 100;
        balancesViewer.getTable().setLayoutData(gridData);

        balancesViewer.getTable().setHeaderVisible(true);
        balancesViewer.getTable().setLinesVisible(true);

        balancesViewer.setContentProvider(ArrayContentProvider.getInstance());

        // Sort by stock name
        balancesViewer.setComparator(new ViewerComparator() {
            @Override
            public int compare(Viewer viewer, Object element1, Object element2) {
                StockWrapper stockWrapper1 = (StockWrapper) element1;
                StockWrapper stockWrapper2 = (StockWrapper) element2;
                return stockWrapper1.stock.getName().compareTo(stockWrapper2.stock.getName());
            }
        });

        TableViewerColumn stockNameColumn = new TableViewerColumn(balancesViewer, SWT.LEFT);
        stockNameColumn.getColumn().setText("Stock");
        stockNameColumn.getColumn().setWidth(300);

        stockNameColumn.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(ViewerCell cell) {
                StockWrapper stockWrapper = (StockWrapper) cell.getElement();
                cell.setText(stockWrapper.stock.getName());
            }
        });

        TableViewerColumn balanceColumn = new TableViewerColumn(balancesViewer, SWT.LEFT);
        balanceColumn.getColumn().setText("Number of Shares");
        balanceColumn.getColumn().setWidth(100);

        balanceColumn.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(ViewerCell cell) {
                StockWrapper stockWrapper = (StockWrapper) cell.getElement();
                cell.setText(stockWrapper.stock.format(stockWrapper.total));
            }
        });

        // Create the pop-up menu
        MenuManager menuMgr = new MenuManager();
        // TODO We are making assumptions about where this editor is placed when
        // we make the following cast to AccountEditor.  Can this be cleaned up?
        menuMgr.add(new ShowDetailsAction(balancesViewer));
        menuMgr.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
        getSite().registerContextMenu(menuMgr, balancesViewer);

        Control control = balancesViewer.getControl();
        Menu menu = menuMgr.createContextMenu(control);
        control.setMenu(menu);

        return composite;
    }

    @Override
    public void setFocus() {
        // Don't bother to do anything.  User can select as required.
    }

    public class ShowDetailsAction extends Action {

        private ISelectionProvider selectionProvider;

        public ShowDetailsAction(ISelectionProvider selectionProvider) {
            super("Show Stock Activity");
            this.selectionProvider = selectionProvider;
        }

        @Override
        public void run() {
            IStructuredSelection selection = (IStructuredSelection) selectionProvider.getSelection();
            Object element = selection.getFirstElement();
            if (element instanceof StockWrapper) {
                Stock stock = ((StockWrapper) element).stock;
                try {
                    ShowStockDetailsHandler.showStockDetails(accountEditor, stock);
                } catch (PartInitException e) {
                    JMoneyPlugin.log(e);
                }
            }
        }
    }
}