/*
* Copyright (c) 2004-2011 Marco Maccaferri and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marco Maccaferri - initial API and implementation
*/
package org.eclipsetrader.ui.internal.views;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.ViewPart;
import org.eclipsetrader.core.feed.ILastClose;
import org.eclipsetrader.core.feed.IPricingListener;
import org.eclipsetrader.core.feed.IQuote;
import org.eclipsetrader.core.feed.ITrade;
import org.eclipsetrader.core.feed.PricingDelta;
import org.eclipsetrader.core.feed.PricingEvent;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.core.markets.IMarketService;
import org.eclipsetrader.core.markets.MarketPricingEnvironment;
import org.eclipsetrader.core.repositories.IRepositoryService;
import org.eclipsetrader.core.repositories.IStoreObject;
import org.eclipsetrader.core.views.IDataProvider;
import org.eclipsetrader.ui.UIConstants;
import org.eclipsetrader.ui.internal.UIActivator;
import org.eclipsetrader.ui.internal.providers.ChangeFactory;
import org.eclipsetrader.ui.internal.providers.LastTradePriceFactory;
import org.eclipsetrader.ui.internal.providers.LastTradeTimeFactory;
import org.eclipsetrader.ui.internal.providers.SecurityNameFactory;
import org.eclipsetrader.ui.internal.providers.TrendFactory;
import org.eclipsetrader.ui.navigator.RepositoryObjectTransfer;
import org.eclipsetrader.ui.navigator.SecurityObjectTransfer;
public class TickersView extends ViewPart {
public static final String VIEW_ID = "org.eclipsetrader.ui.views.tickers";
public static final String K_SECURITIES = "securities";
private BoxViewer viewer;
private IDialogSettings dialogSettings;
private Action deleteAction;
private Action settingsAction;
private List<TickerViewItem> input;
private MarketPricingEnvironment pricingEnvironment;
private IDataProvider[] providers;
private IPricingListener pricingListener = new IPricingListener() {
@Override
public void pricingUpdate(PricingEvent event) {
onPricingUpdate(event);
}
};
public TickersView() {
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento)
*/
@Override
public void init(IViewSite site, IMemento memento) throws PartInitException {
super.init(site, memento);
ImageRegistry imageRegistry = UIActivator.getDefault().getImageRegistry();
dialogSettings = UIActivator.getDefault().getDialogSettings().getSection(site.getId());
if (dialogSettings == null) {
dialogSettings = UIActivator.getDefault().getDialogSettings().addNewSection(site.getId());
}
deleteAction = new Action("Delete") {
@Override
public void run() {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
input.removeAll(selection.toList());
Object[] o = selection.toArray();
ISecurity[] s = new ISecurity[o.length];
for (int i = 0; i < s.length; i++) {
s[i] = ((TickerViewItem) o[i]).getSecurity();
}
pricingEnvironment.removeSecurities(s);
saveInput();
viewer.refresh();
}
};
deleteAction.setImageDescriptor(imageRegistry.getDescriptor(UIConstants.DELETE_EDIT_ICON));
deleteAction.setDisabledImageDescriptor(imageRegistry.getDescriptor(UIConstants.DELETE_EDIT_DISABLED_ICON));
deleteAction.setId(ActionFactory.DELETE.getId());
deleteAction.setActionDefinitionId("org.eclipse.ui.edit.delete"); //$NON-NLS-1$
deleteAction.setEnabled(false);
settingsAction = new TickersSettingsAction(site.getShell(), this);
IActionBars actionBars = site.getActionBars();
actionBars.setGlobalActionHandler(settingsAction.getId(), settingsAction);
actionBars.setGlobalActionHandler(deleteAction.getId(), deleteAction);
actionBars.updateActionBars();
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(Composite parent) {
viewer = createViewer(parent);
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
deleteAction.setEnabled(!event.getSelection().isEmpty());
}
});
viewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE, new Transfer[] {
SecurityObjectTransfer.getInstance(),
RepositoryObjectTransfer.getInstance(),
}, new ViewerDropAdapter(viewer) {
@Override
public boolean validateDrop(Object target, int operation, TransferData transferType) {
return SecurityObjectTransfer.getInstance().isSupportedType(transferType) || RepositoryObjectTransfer.getInstance().isSupportedType(transferType);
}
@Override
public boolean performDrop(Object data) {
final IAdaptable[] contents = (IAdaptable[]) data;
for (int i = 0; i < contents.length; i++) {
ISecurity security = (ISecurity) contents[i].getAdapter(ISecurity.class);
if (security != null) {
TickerViewItem viewItem = new TickerViewItem(security);
input.add(viewItem);
pricingEnvironment.addSecurity(security);
viewItem.setTrade(pricingEnvironment.getTrade(security));
viewItem.setQuote(pricingEnvironment.getQuote(security));
viewItem.setLastClose(pricingEnvironment.getLastClose(security));
IAdaptable[] newValues = new IAdaptable[providers.length];
for (int ii = 0; ii < newValues.length; ii++) {
newValues[ii] = providers[ii] != null ? providers[ii].getValue(viewItem) : null;
}
viewItem.setValues(newValues);
}
}
viewer.refresh();
saveInput();
return true;
}
});
providers = new IDataProvider[] {
new SecurityNameFactory().createProvider(),
new LastTradeTimeFactory().createProvider(),
new LastTradePriceFactory().createProvider(),
new ChangeFactory().createProvider(),
new TrendFactory().createProvider(),
};
IRepositoryService repository = getRepositoryService();
input = new ArrayList<TickerViewItem>();
List<ISecurity> l = new ArrayList<ISecurity>();
String[] uri = dialogSettings.getArray(K_SECURITIES);
if (uri != null) {
for (int i = 0; i < uri.length; i++) {
try {
ISecurity security = repository.getSecurityFromURI(new URI(uri[i]));
l.add(security);
input.add(new TickerViewItem(security));
} catch (Exception e) {
Status status = new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, "Error loading security " + uri[i], e);
UIActivator.getDefault().getLog().log(status);
}
}
}
pricingEnvironment = new MarketPricingEnvironment(getMarketService(), l.toArray(new ISecurity[l.size()]));
pricingEnvironment.addPricingListener(pricingListener);
for (TickerViewItem viewItem : input) {
viewItem.setTrade(pricingEnvironment.getTrade(viewItem.getSecurity()));
viewItem.setQuote(pricingEnvironment.getQuote(viewItem.getSecurity()));
viewItem.setLastClose(pricingEnvironment.getLastClose(viewItem.getSecurity()));
IAdaptable[] newValues = new IAdaptable[providers.length];
for (int ii = 0; ii < newValues.length; ii++) {
newValues[ii] = providers[ii] != null ? providers[ii].getValue(viewItem) : null;
}
viewItem.setValues(newValues);
}
MenuManager menuMgr = new MenuManager("#popupMenu", "popupMenu"); //$NON-NLS-1$ //$NON-NLS-2$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager menuManager) {
menuManager.add(deleteAction);
menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
});
viewer.getControl().setMenu(menuMgr.createContextMenu(viewer.getControl()));
getSite().registerContextMenu(menuMgr, getSite().getSelectionProvider());
getViewSite().setSelectionProvider(viewer);
viewer.setInput(input);
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
if (viewer != null && !viewer.getControl().isDisposed()) {
viewer.getControl().setFocus();
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#dispose()
*/
@Override
public void dispose() {
if (pricingEnvironment != null) {
pricingEnvironment.removePricingListener(pricingListener);
pricingEnvironment.dispose();
}
saveInput();
super.dispose();
}
protected void saveInput() {
String[] ar = new String[input.size()];
for (int i = 0; i < ar.length; i++) {
IStoreObject storeObject = (IStoreObject) input.get(i).getSecurity().getAdapter(IStoreObject.class);
ar[i] = storeObject.getStore().toURI().toString();
}
dialogSettings.put(K_SECURITIES, ar);
}
protected BoxViewer createViewer(Composite parent) {
BoxViewer viewer = new BoxViewer(parent);
viewer.setUseHashlookup(true);
viewer.setLabelProvider(new ViewItemLabelProvider());
viewer.setContentProvider(new ArrayContentProvider());
return viewer;
}
@SuppressWarnings("unchecked")
protected int compareValues(IAdaptable[] v1, IAdaptable[] v2, int sortColumn) {
if (sortColumn < 0 || sortColumn >= v1.length || sortColumn >= v2.length) {
return 0;
}
if (v1[sortColumn] == null || v2[sortColumn] == null) {
return 0;
}
Object o1 = v1[sortColumn].getAdapter(Comparable.class);
Object o2 = v2[sortColumn].getAdapter(Comparable.class);
if (o1 != null && o2 != null) {
return ((Comparable) o1).compareTo(o2);
}
o1 = v1[sortColumn].getAdapter(Number.class);
o2 = v2[sortColumn].getAdapter(Number.class);
if (o1 != null && o2 != null) {
if (((Number) o1).doubleValue() < ((Number) o2).doubleValue()) {
return -1;
}
if (((Number) o1).doubleValue() > ((Number) o2).doubleValue()) {
return 1;
}
return 0;
}
return 0;
}
protected void onPricingUpdate(PricingEvent event) {
final List<TickerViewItem> l = new ArrayList<TickerViewItem>();
synchronized (input) {
for (TickerViewItem viewItem : input) {
if (viewItem.getSecurity() == event.getSecurity()) {
for (PricingDelta delta : event.getDelta()) {
if (delta.getNewValue() instanceof ITrade) {
viewItem.setTrade((ITrade) delta.getNewValue());
}
if (delta.getNewValue() instanceof IQuote) {
viewItem.setQuote((IQuote) delta.getNewValue());
}
if (delta.getNewValue() instanceof ILastClose) {
viewItem.setLastClose((ILastClose) delta.getNewValue());
}
}
IAdaptable[] oldValues = viewItem.getValues();
IAdaptable[] newValues = new IAdaptable[providers.length];
for (int i = 0; i < newValues.length; i++) {
newValues[i] = providers[i] != null ? providers[i].getValue(viewItem) : null;
}
if (!valuesEquals(oldValues, newValues)) {
viewItem.setValues(newValues);
l.add(viewItem);
}
}
}
}
if (!viewer.getControl().isDisposed()) {
try {
viewer.getControl().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (!viewer.getControl().isDisposed()) {
viewer.update(l.toArray(), null);
}
}
});
} catch (SWTException e) {
// Do nothing
}
}
}
protected boolean valuesEquals(IAdaptable[] oldValues, IAdaptable[] newValues) {
if (oldValues == newValues) {
return true;
}
if (oldValues == null && newValues != null || oldValues != null && newValues == null) {
return false;
}
if (oldValues.length != newValues.length) {
return false;
}
for (int i = 0; i < newValues.length; i++) {
if (oldValues[i] == newValues[i]) {
continue;
}
if (oldValues[i] == null && newValues[i] != null || oldValues[i] != null && newValues[i] == null) {
return false;
}
if (!newValues[i].equals(oldValues[i])) {
return false;
}
}
return true;
}
protected IRepositoryService getRepositoryService() {
return UIActivator.getDefault().getRepositoryService();
}
protected IMarketService getMarketService() {
return UIActivator.getDefault().getMarketService();
}
public TickerViewItem[] getViewItems() {
return input.toArray(new TickerViewItem[input.size()]);
}
public void setViewItems(TickerViewItem[] input) {
for (TickerViewItem viewItem : input) {
pricingEnvironment.removeSecurity(viewItem.getSecurity());
}
this.input = new ArrayList<TickerViewItem>(Arrays.asList(input));
saveInput();
for (TickerViewItem viewItem : input) {
pricingEnvironment.addSecurity(viewItem.getSecurity());
viewItem.setTrade(pricingEnvironment.getTrade(viewItem.getSecurity()));
viewItem.setQuote(pricingEnvironment.getQuote(viewItem.getSecurity()));
viewItem.setLastClose(pricingEnvironment.getLastClose(viewItem.getSecurity()));
IAdaptable[] newValues = new IAdaptable[providers.length];
for (int ii = 0; ii < newValues.length; ii++) {
newValues[ii] = providers[ii] != null ? providers[ii].getValue(viewItem) : null;
}
viewItem.setValues(newValues);
}
viewer.setInput(this.input);
}
}