/* * 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.ats.monitor; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.databinding.observable.list.IListChangeListener; import org.eclipse.core.databinding.observable.list.ListChangeEvent; import org.eclipse.core.databinding.observable.list.ListDiffVisitor; import org.eclipse.core.databinding.observable.map.IObservableMap; import org.eclipse.core.runtime.ListenerList; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.GroupMarker; 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.databinding.viewers.ObservableListTreeContentProvider; import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.ILabelDecorator; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.TreeColumn; 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.part.ViewPart; import org.eclipsetrader.core.ats.ITradingSystem; import org.eclipsetrader.core.ats.ITradingSystemService; import org.eclipsetrader.core.internal.CoreActivator; import org.eclipsetrader.core.internal.ats.TradingSystemProperties; import org.eclipsetrader.ui.internal.UIActivator; import org.eclipsetrader.ui.internal.ats.ViewColumn; import org.eclipsetrader.ui.internal.ats.ViewerObservableMap; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; public class TradingSystemsViewPart extends ViewPart { public static final String VIEW_ID = "org.eclipsetrader.ui.views.ats.monitor"; //$NON-NLS-1$ static final String COLUMNS = "COLUMNS"; //$NON-NLS-1$ static final String COLUMN_NAMES = "COLUMN_NAMES"; //$NON-NLS-1$ static final String COLUMN_WIDTHS = "COLUMN_WIDTHS"; //$NON-NLS-1$ static final String LABEL_COLUMN = "_label_"; //$NON-NLS-1$ CoreActivator activator; ITradingSystemService tradingSystemService; TreeViewer viewer; TradingSystemsViewModel model; private Action settingsAction; IDialogSettings dialogSettings; private PropertyChangeListener columnPropertiesChangeListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { int index = model.getDataProviders().indexOf(evt.getSource()); if (index != -1) { viewer.getTree().getColumn(index + 1).setText((String) evt.getNewValue()); } } }; private ControlListener columnControlListener = new ControlAdapter() { @Override public void controlResized(ControlEvent e) { IDialogSettings settings = dialogSettings.getSection(COLUMN_WIDTHS); TreeColumn treeColumn = (TreeColumn) e.widget; int index = treeColumn.getParent().indexOf(treeColumn); if (index == 0) { settings.put(LABEL_COLUMN, treeColumn.getWidth()); } else { ViewColumn viewColumn = model.getDataProviders().get(index - 1); settings.put(viewColumn.getDataProviderFactory().getId(), treeColumn.getWidth()); } } }; public TradingSystemsViewPart() { } /* (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); BundleContext bundleContext = UIActivator.getDefault().getBundle().getBundleContext(); ServiceReference<ITradingSystemService> serviceReference = bundleContext.getServiceReference(ITradingSystemService.class); tradingSystemService = bundleContext.getService(serviceReference); activator = CoreActivator.getDefault(); IDialogSettings rootDialogSettings = UIActivator.getDefault().getDialogSettings(); dialogSettings = rootDialogSettings.getSection(VIEW_ID); if (dialogSettings == null) { dialogSettings = rootDialogSettings.addNewSection(VIEW_ID); dialogSettings.put(COLUMNS, new String[] { "org.eclipsetrader.ui.providers.LastTrade", //$NON-NLS-1$ "org.eclipsetrader.ui.providers.BidPrice", //$NON-NLS-1$ "org.eclipsetrader.ui.providers.AskPrice", //$NON-NLS-1$ "org.eclipsetrader.ui.providers.Position", //$NON-NLS-1$ "org.eclipsetrader.ui.providers.LastTradeDateTime", //$NON-NLS-1$ "org.eclipsetrader.ui.providers.gain", //$NON-NLS-1$ }); IDialogSettings section = dialogSettings.addNewSection(COLUMN_NAMES); section.put("org.eclipsetrader.ui.providers.LastTrade", "Last"); //$NON-NLS-1$ section.put("org.eclipsetrader.ui.providers.BidPrice", "Bid"); //$NON-NLS-1$ section.put("org.eclipsetrader.ui.providers.AskPrice", "Ask"); //$NON-NLS-1$ section.put("org.eclipsetrader.ui.providers.Position", "Position"); //$NON-NLS-1$ section.put("org.eclipsetrader.ui.providers.LastTradeDateTime", "Date / Time"); //$NON-NLS-1$ section.put("org.eclipsetrader.ui.providers.gain", "Gain"); //$NON-NLS-1$ dialogSettings.addNewSection(COLUMN_WIDTHS); } settingsAction = new SettingsAction(site.getShell(), this); IActionBars actionBars = site.getActionBars(); actionBars.setGlobalActionHandler(settingsAction.getId(), settingsAction); actionBars.updateActionBars(); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPartControl(Composite parent) { viewer = new TreeViewer(parent, SWT.FULL_SELECTION | SWT.MULTI); viewer.getTree().setHeaderVisible(true); viewer.getTree().setLinesVisible(false); createContextMenu(); model = new TradingSystemsViewModel(tradingSystemService); String[] columns = dialogSettings.getArray(COLUMNS); IDialogSettings namesSection = dialogSettings.getSection(COLUMN_NAMES); List<ViewColumn> list = new ArrayList<ViewColumn>(); for (int i = 0; i < columns.length; i++) { String name = namesSection.get(columns[i]); list.add(new ViewColumn(name, activator.getDataProviderFactory(columns[i]))); } model.setDataProviders(list); for (final TradingSystemItem item : model.getList()) { PropertyChangeSupport changeSupport = (PropertyChangeSupport) item.getTradingSystem().getAdapter(PropertyChangeSupport.class); if (changeSupport != null) { changeSupport.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (viewer.getControl().isDisposed()) { return; } viewer.refresh(item); } }); } }); } } final ObservableListTreeContentProvider contentProvider = new ObservableListTreeContentProvider(model, model); viewer.setContentProvider(contentProvider); IDialogSettings widthSettings = dialogSettings.getSection(COLUMN_WIDTHS); TreeViewerColumn viewerColumn = new TreeViewerColumn(viewer, SWT.NONE); int width = 300; if (widthSettings.get(LABEL_COLUMN) != null) { width = widthSettings.getInt(LABEL_COLUMN); } viewerColumn.getColumn().setWidth(width); viewerColumn.getColumn().addControlListener(columnControlListener); final List<IObservableMap> properties = new ArrayList<IObservableMap>(); properties.add(new ViewerObservableMap(contentProvider.getKnownElements(), LABEL_COLUMN)); for (ViewColumn column : model.getDataProviders()) { viewerColumn = new TreeViewerColumn(viewer, SWT.RIGHT); viewerColumn.getColumn().setText(column.getName()); width = 100; if (widthSettings.get(column.getDataProviderFactory().getId()) != null) { width = widthSettings.getInt(column.getDataProviderFactory().getId()); } viewerColumn.getColumn().setWidth(width); viewerColumn.getColumn().addControlListener(columnControlListener); column.addPropertyChangeListener(ViewColumn.PROP_NAME, columnPropertiesChangeListener); properties.add(new ViewerObservableMap(contentProvider.getKnownElements(), column.getDataProviderFactory().getId())); } createLabelProvider(properties.toArray(new IObservableMap[properties.size()])); model.getObservableDataProviders().addListChangeListener(new IListChangeListener() { @Override public void handleListChange(ListChangeEvent event) { event.diff.accept(new ListDiffVisitor() { @Override public void handleRemove(int index, Object element) { TreeColumn treeColumn = viewer.getTree().getColumn(index + 1); treeColumn.dispose(); ViewColumn column = (ViewColumn) element; column.removePropertyChangeListener(ViewColumn.PROP_NAME, columnPropertiesChangeListener); IObservableMap observableMap = properties.remove(index + 1); if (observableMap != null) { observableMap.dispose(); } } @Override public void handleAdd(int index, Object element) { ViewColumn column = (ViewColumn) element; TreeViewerColumn viewerColumn = new TreeViewerColumn(viewer, SWT.RIGHT, index + 1); viewerColumn.getColumn().setText(column.getName()); int width = 100; IDialogSettings widthSettings = dialogSettings.getSection(COLUMN_WIDTHS); if (widthSettings.get(column.getDataProviderFactory().getId()) != null) { width = widthSettings.getInt(column.getDataProviderFactory().getId()); } viewerColumn.getColumn().setWidth(width); viewerColumn.getColumn().addControlListener(columnControlListener); column.addPropertyChangeListener(ViewColumn.PROP_NAME, columnPropertiesChangeListener); properties.add(index + 1, new ViewerObservableMap(contentProvider.getKnownElements(), column.getDataProviderFactory().getId())); } }); createLabelProvider(properties.toArray(new IObservableMap[properties.size()])); IDialogSettings namesSection = dialogSettings.getSection(COLUMN_NAMES); List<String> list = new ArrayList<String>(); for (ViewColumn column : model.getDataProviders()) { list.add(column.getDataProviderFactory().getId()); namesSection.put(column.getDataProviderFactory().getId(), column.getName()); } dialogSettings.put(COLUMNS, list.toArray(new String[list.size()])); } }); viewer.setComparator(new ViewerComparator()); getSite().setSelectionProvider(viewer); viewer.setInput(model); viewer.expandAll(); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#dispose() */ @Override public void dispose() { model.dispose(); super.dispose(); } private void createLabelProvider(IObservableMap[] properties) { ObservableMapLabelProvider labelProvider = new ObservableMapLabelProvider(properties) { @Override public Image getColumnImage(Object element, int columnIndex) { if (columnIndex == 0) { if (element instanceof TradingSystemItem) { return UIActivator.getImageFromRegistry(UIActivator.IMG_TRADING_SYSTEM); } if (element instanceof TradingSystemInstrumentItem) { return UIActivator.getImageFromRegistry(UIActivator.IMG_INSTRUMENT); } } return super.getColumnImage(element, columnIndex); } }; ILabelDecorator labelDecorator = new ILabelDecorator() { private final ListenerList listeners = new ListenerList(ListenerList.IDENTITY); @Override public void addListener(ILabelProviderListener listener) { listeners.add(listener); } @Override public void removeListener(ILabelProviderListener listener) { listeners.remove(listener); } @Override public boolean isLabelProperty(Object element, String property) { return LABEL_COLUMN.equals(property); } @Override public void dispose() { listeners.clear(); } @Override public String decorateText(String text, Object element) { if (element instanceof TradingSystemItem) { StringBuilder sb = new StringBuilder(); TradingSystemItem item = (TradingSystemItem) element; switch (item.getTradingSystem().getStatus()) { case ITradingSystem.STATUS_STARTING: sb.append("starting"); break; case ITradingSystem.STATUS_STARTED: sb.append("started"); break; case ITradingSystem.STATUS_STOPPING: sb.append("stopping"); break; case ITradingSystem.STATUS_STOPPED: sb.append("stopped"); break; } TradingSystemProperties properties = (TradingSystemProperties) item.getTradingSystem().getAdapter(TradingSystemProperties.class); if (properties != null) { if (properties.isAutostart()) { if (sb.length() != 0) { sb.append(", "); } sb.append("autostart"); } } if (sb.length() != 0) { sb.insert(0, " ["); sb.append("]"); } return text + sb.toString(); } return text; } @Override public Image decorateImage(Image image, Object element) { return null; } }; viewer.setLabelProvider(new TableDecoratingLabelProvider(labelProvider, labelDecorator)); } private void createContextMenu() { 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(new Separator("group.new")); //$NON-NLS-1$ menuManager.add(new GroupMarker("group.goto")); //$NON-NLS-1$ menuManager.add(new Separator("group.open")); //$NON-NLS-1$ menuManager.add(new GroupMarker("group.openWith")); //$NON-NLS-1$ menuManager.add(new Separator("group.trade")); //$NON-NLS-1$ menuManager.add(new GroupMarker("group.tradeWith")); //$NON-NLS-1$ menuManager.add(new Separator("group.show")); //$NON-NLS-1$ menuManager.add(new Separator("group.edit")); //$NON-NLS-1$ menuManager.add(new GroupMarker("group.reorganize")); //$NON-NLS-1$ menuManager.add(new GroupMarker("group.port")); //$NON-NLS-1$ menuManager.add(new Separator("group.generate")); //$NON-NLS-1$ menuManager.add(new Separator("group.search")); //$NON-NLS-1$ menuManager.add(new Separator("group.build")); //$NON-NLS-1$ menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); menuManager.add(new Separator("group.properties")); //$NON-NLS-1$ menuManager.appendToGroup("group.show", new Action("Expand All") { //$NON-NLS-1$ @Override public void run() { IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); for (Iterator<?> iter = selection.iterator(); iter.hasNext();) { viewer.expandToLevel(iter.next(), AbstractTreeViewer.ALL_LEVELS); } } }); } }); viewer.getControl().setMenu(menuMgr.createContextMenu(viewer.getControl())); getSite().registerContextMenu(menuMgr, getSite().getSelectionProvider()); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#setFocus() */ @Override public void setFocus() { viewer.getControl().setFocus(); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) */ @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public Object getAdapter(Class adapter) { if (adapter.isAssignableFrom(model.getClass())) { return model; } return super.getAdapter(adapter); } }