/*
* 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.news.internal.ui;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
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.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.core.repositories.IRepositoryService;
import org.eclipsetrader.news.core.HeadLineStatus;
import org.eclipsetrader.news.core.IHeadLine;
import org.eclipsetrader.news.core.INewsProvider;
import org.eclipsetrader.news.core.INewsService;
import org.eclipsetrader.news.core.INewsServiceListener;
import org.eclipsetrader.news.core.NewsEvent;
import org.eclipsetrader.news.internal.Activator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
public class HeadLineViewer extends ViewPart {
public static final String VIEW_ID = "org.eclipsetrader.ui.views.headlines";
private static final String K_VIEWS = "Views";
private static final String K_URI = "uri";
private static final String K_COLUMNS = "columns";
private Action refreshAction;
private Action showPreviousAction;
private Action showNextAction;
private Action openAction;
private Action openNewWindowAction;
private Action markAsReadAction;
private Action markAllAsReadAction;
private TableViewer viewer;
private IDialogSettings dialogSettings;
private INewsService service;
private List<IHeadLine> input;
private ISecurity security;
private ControlAdapter controlListener = new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
TableColumn tableColumn = (TableColumn) e.widget;
int index = viewer.getTable().indexOf(tableColumn);
if (dialogSettings != null) {
IDialogSettings columnsSection = dialogSettings.getSection(K_COLUMNS);
if (columnsSection == null) {
columnsSection = dialogSettings.addNewSection(K_COLUMNS);
}
columnsSection.put(String.valueOf(index), tableColumn.getWidth());
}
}
};
private INewsServiceListener newsListener = new INewsServiceListener() {
@Override
public void newsServiceUpdate(NewsEvent event) {
for (HeadLineStatus status : event.getStatus()) {
if (security != null && !status.getHeadLine().contains(security)) {
continue;
}
if (status.getKind() == HeadLineStatus.ADDED) {
input.add(status.getHeadLine());
}
else if (status.getKind() == HeadLineStatus.REMOVED) {
input.remove(status.getHeadLine());
}
}
if (!viewer.getControl().isDisposed()) {
try {
viewer.getControl().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (!viewer.getControl().isDisposed()) {
viewer.refresh();
updateTitleImage();
}
}
});
} catch (SWTException e) {
if (e.code != SWT.ERROR_WIDGET_DISPOSED) {
throw e;
}
}
}
}
};
private ISelectionListener selectionListener = new ISelectionListener() {
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
viewer.setSelection(selection, true);
}
};
public HeadLineViewer() {
}
/* (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);
IDialogSettings bundleDialogSettings = Activator.getDefault().getDialogSettings();
if (site.getSecondaryId() != null) {
try {
dialogSettings = bundleDialogSettings.getSection(K_VIEWS).getSection(site.getSecondaryId());
URI uri = new URI(dialogSettings.get(K_URI));
IRepositoryService repositoryService = Activator.getDefault().getRepositoryService();
security = repositoryService.getSecurityFromURI(uri);
if (security != null) {
setPartName(NLS.bind("{0} - {1}", new Object[] {
security.getName(), getPartName()
}));
}
} catch (Exception e) {
Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error loading view " + site.getSecondaryId(), e);
Activator.getDefault().getLog().log(status);
}
}
if (dialogSettings == null) {
dialogSettings = bundleDialogSettings.getSection(getClass().getName());
if (dialogSettings == null) {
dialogSettings = bundleDialogSettings.addNewSection(getClass().getName());
}
}
refreshAction = new Action("Refresh") {
@Override
public void run() {
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
INewsProvider[] providers = service.getProviders();
for (int i = 0; i < providers.length; i++) {
if (store.getBoolean(providers[i].getId())) {
providers[i].refresh();
}
}
}
};
refreshAction.setImageDescriptor(Activator.getImageDescriptor("icons/elcl16/refresh.gif")); //$NON-NLS-1$
refreshAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/dlcl16/refresh.gif")); //$NON-NLS-1$
showPreviousAction = new Action("Previous") {
@Override
public void run() {
IHeadLine headLine = getPreviousHeadLine();
if (headLine != null) {
viewer.setSelection(new StructuredSelection(headLine), true);
doOpenHeadLine(headLine, false);
}
}
};
showPreviousAction.setImageDescriptor(Activator.getImageDescriptor("icons/elcl16/prev_nav.gif")); //$NON-NLS-1$
showPreviousAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/dlcl16/prev_nav.gif")); //$NON-NLS-1$
showNextAction = new Action("Next") {
@Override
public void run() {
IHeadLine headLine = getNextHeadLine();
if (headLine != null) {
viewer.setSelection(new StructuredSelection(headLine), true);
doOpenHeadLine(headLine, false);
}
}
};
showNextAction.setImageDescriptor(Activator.getImageDescriptor("icons/elcl16/next_nav.gif")); //$NON-NLS-1$
showNextAction.setDisabledImageDescriptor(Activator.getImageDescriptor("icons/dlcl16/next_nav.gif")); //$NON-NLS-1$
openAction = new Action("Open") {
@Override
public void run() {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
if (!selection.isEmpty()) {
IHeadLine headLine = (IHeadLine) selection.getFirstElement();
doOpenHeadLine(headLine, false);
}
}
};
openNewWindowAction = new Action("Open in New Browser") {
@Override
public void run() {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
if (!selection.isEmpty()) {
IHeadLine headLine = (IHeadLine) selection.getFirstElement();
doOpenHeadLine(headLine, true);
}
}
};
markAsReadAction = new Action("Mark as Read") {
@Override
public void run() {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
List<?> list = selection.toList();
final IHeadLine[] headLines = list.toArray(new IHeadLine[list.size()]);
for (int i = 0; i < headLines.length; i++) {
headLines[i].setReaded(true);
}
service.updateHeadLines(headLines);
}
};
markAllAsReadAction = new Action("Mark All as Read") {
@Override
public void run() {
final IHeadLine[] headLines = input.toArray(new IHeadLine[input.size()]);
for (int i = 0; i < headLines.length; i++) {
headLines[i].setReaded(true);
}
service.updateHeadLines(headLines);
}
};
IToolBarManager toolBarManager = site.getActionBars().getToolBarManager();
toolBarManager.add(new Separator("begin")); //$NON-NLS-1$
toolBarManager.add(showPreviousAction);
toolBarManager.add(showNextAction);
toolBarManager.add(new Separator("additions")); //$NON-NLS-1$
toolBarManager.add(refreshAction);
toolBarManager.add(new Separator("end")); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(Composite parent) {
createViewer(parent);
input = new ArrayList<IHeadLine>(Arrays.asList(getHeadLines()));
viewer.setInput(input);
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"));
menuManager.add(new GroupMarker("group.goto"));
menuManager.add(new Separator("group.open"));
menuManager.add(new GroupMarker("group.openWith"));
menuManager.add(new Separator("group.show"));
menuManager.add(new Separator("group.edit"));
menuManager.add(new GroupMarker("group.reorganize"));
menuManager.add(new GroupMarker("group.port"));
menuManager.add(new Separator("group.generate"));
menuManager.add(new Separator("group.search"));
menuManager.add(new Separator("group.build"));
menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
menuManager.add(new Separator("group.properties"));
menuManager.appendToGroup("group.open", openAction);
menuManager.appendToGroup("group.open", openNewWindowAction);
menuManager.appendToGroup("group.edit", markAsReadAction);
menuManager.appendToGroup("group.edit", markAllAsReadAction);
}
});
viewer.getControl().setMenu(menuMgr.createContextMenu(viewer.getControl()));
if (getSite() != null) {
getSite().registerContextMenu(menuMgr, getSite().getSelectionProvider());
getSite().getPage().addSelectionListener(selectionListener);
viewer.setSelection(getSite().getPage().getSelection(), true);
}
}
protected void updateTitleImage() {
if (hasUnreadedHeadlines()) {
setTitleImage(Activator.getDefault().getImageRegistry().get("new_headlines_icon"));
}
else {
setTitleImage(Activator.getDefault().getImageRegistry().get("normal_icon"));
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#dispose()
*/
@Override
public void dispose() {
if (service != null) {
service.removeNewsServiceListener(newsListener);
}
getSite().getPage().removeSelectionListener(selectionListener);
super.dispose();
}
protected void createViewer(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.FULL_SELECTION);
viewer.getTable().setHeaderVisible(true);
viewer.getTable().setLinesVisible(false);
IDialogSettings columnsSection = dialogSettings != null ? dialogSettings.getSection(K_COLUMNS) : null;
TableColumn tableColumn = new TableColumn(viewer.getTable(), SWT.LEFT);
tableColumn.setText("Date");
tableColumn.setWidth(columnsSection != null && columnsSection.get(String.valueOf(viewer.getTable().indexOf(tableColumn))) != null ? columnsSection.getInt(String.valueOf(viewer.getTable().indexOf(tableColumn))) : 160);
tableColumn.addControlListener(controlListener);
tableColumn = new TableColumn(viewer.getTable(), SWT.LEFT);
tableColumn.setText("Title");
tableColumn.setWidth(columnsSection != null && columnsSection.get(String.valueOf(viewer.getTable().indexOf(tableColumn))) != null ? columnsSection.getInt(String.valueOf(viewer.getTable().indexOf(tableColumn))) : 300);
tableColumn.addControlListener(controlListener);
tableColumn = new TableColumn(viewer.getTable(), SWT.LEFT);
tableColumn.setText("Security");
tableColumn.setWidth(columnsSection != null && columnsSection.get(String.valueOf(viewer.getTable().indexOf(tableColumn))) != null ? columnsSection.getInt(String.valueOf(viewer.getTable().indexOf(tableColumn))) : 250);
tableColumn.addControlListener(controlListener);
tableColumn = new TableColumn(viewer.getTable(), SWT.LEFT);
tableColumn.setText("Source");
tableColumn.setWidth(columnsSection != null && columnsSection.get(String.valueOf(viewer.getTable().indexOf(tableColumn))) != null ? columnsSection.getInt(String.valueOf(viewer.getTable().indexOf(tableColumn))) : 200);
tableColumn.addControlListener(controlListener);
viewer.setLabelProvider(new HeadLineLabelProvider());
viewer.setContentProvider(new ArrayContentProvider());
viewer.setSorter(new ViewerSorter() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
int cat1 = category(e1);
int cat2 = category(e2);
if (cat1 != cat2) {
return cat1 - cat2;
}
return ((IHeadLine) e2).getDate().compareTo(((IHeadLine) e1).getDate());
}
@Override
public int category(Object element) {
IHeadLine headLine = (IHeadLine) element;
return headLine.isRecent() ? 0 : 1;
}
});
viewer.addOpenListener(new IOpenListener() {
@Override
public void open(OpenEvent event) {
if (!event.getSelection().isEmpty()) {
IHeadLine headLine = (IHeadLine) ((IStructuredSelection) event.getSelection()).getFirstElement();
doOpenHeadLine(headLine, false);
}
}
});
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
openAction.setEnabled(!event.getSelection().isEmpty());
markAsReadAction.setEnabled(!event.getSelection().isEmpty());
markAllAsReadAction.setEnabled(input.size() != 0);
}
});
}
protected void doOpenHeadLine(IHeadLine headLine, boolean newWindow) {
IWorkbenchPage page = getSite().getPage();
IViewReference[] refs = page.getViewReferences();
for (int i = 0; i < refs.length; i++) {
if (refs[i].getId().equals(NewsViewer.VIEW_ID)) {
NewsViewer viewer = (NewsViewer) refs[i].getPart(true);
if (headLine.equals(viewer.getHeadLine())) {
if (!page.isPartVisible(viewer)) {
page.bringToTop(viewer);
}
return;
}
}
}
try {
IViewPart viewPart = newWindow ? page.showView(NewsViewer.VIEW_ID, UUID.randomUUID().toString(), IWorkbenchPage.VIEW_ACTIVATE) : page.showView(NewsViewer.VIEW_ID, null, IWorkbenchPage.VIEW_VISIBLE);
((NewsViewer) viewPart).setHeadLine(headLine);
headLine.setReaded(true);
if (service != null) {
service.updateHeadLines(new IHeadLine[] {
headLine
});
}
} catch (PartInitException e) {
Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, 0, "Unexpected error activating browser", null);
Activator.log(status);
}
}
protected int indexOf(IHeadLine headLine) {
TableItem[] tableItem = viewer.getTable().getItems();
for (int i = 0; i < tableItem.length; i++) {
if (headLine.equals(tableItem[i].getData())) {
return i;
}
}
return -1;
}
protected IHeadLine getNextHeadLine() {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
if (!selection.isEmpty()) {
int index = indexOf((IHeadLine) selection.getFirstElement());
if (index == -1) {
if (viewer.getTable().getItemCount() == 0) {
return null;
}
return (IHeadLine) viewer.getTable().getItem(0).getData();
}
index++;
if (index < viewer.getTable().getItemCount()) {
return (IHeadLine) viewer.getTable().getItem(index).getData();
}
}
if (viewer.getTable().getItemCount() == 0) {
return null;
}
return (IHeadLine) viewer.getTable().getItem(0).getData();
}
protected IHeadLine getPreviousHeadLine() {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
if (!selection.isEmpty()) {
int index = indexOf((IHeadLine) selection.getFirstElement());
if (index == -1) {
if (viewer.getTable().getItemCount() == 0) {
return null;
}
return (IHeadLine) viewer.getTable().getItem(viewer.getTable().getItemCount() - 1).getData();
}
index--;
if (index >= 0) {
return (IHeadLine) viewer.getTable().getItem(index).getData();
}
}
if (viewer.getTable().getItemCount() == 0) {
return null;
}
return (IHeadLine) viewer.getTable().getItem(viewer.getTable().getItemCount() - 1).getData();
}
TableViewer getViewer() {
return viewer;
}
protected IHeadLine[] getHeadLines() {
IHeadLine[] result = new IHeadLine[0];
BundleContext context = Activator.getDefault().getBundle().getBundleContext();
ServiceReference serviceReference = context.getServiceReference(INewsService.class.getName());
if (serviceReference != null) {
service = (INewsService) context.getService(serviceReference);
if (service != null) {
if (security != null) {
result = service.getHeadLinesFor(security);
}
else {
result = service.getHeadLines();
}
service.addNewsServiceListener(newsListener);
}
context.ungetService(serviceReference);
}
return result;
}
protected boolean hasUnreadedHeadlines() {
for (IHeadLine headLine : input) {
if (!headLine.isReaded()) {
return true;
}
}
return false;
}
}