org.eclipsetrader.ui.internal.charts.views.ChartViewPart.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipsetrader.ui.internal.charts.views.ChartViewPart.java

Source

/*
 * 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.charts.views;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URI;
import java.util.Collections;
import java.util.Comparator;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
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.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.printing.PrintDialog;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.dialogs.PropertyDialogAction;
import org.eclipse.ui.part.ViewPart;
import org.eclipsetrader.core.charts.OHLCDataSeries;
import org.eclipsetrader.core.charts.repository.IChartTemplate;
import org.eclipsetrader.core.feed.IHistory;
import org.eclipsetrader.core.feed.TimeSpan;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.core.internal.charts.repository.ChartTemplate;
import org.eclipsetrader.core.repositories.IPropertyConstants;
import org.eclipsetrader.core.repositories.IRepositoryService;
import org.eclipsetrader.core.views.IViewChangeListener;
import org.eclipsetrader.core.views.IViewItem;
import org.eclipsetrader.core.views.ViewEvent;
import org.eclipsetrader.ui.charts.BaseChartViewer;
import org.eclipsetrader.ui.charts.ChartCanvas;
import org.eclipsetrader.ui.charts.ChartObjectFactoryTransfer;
import org.eclipsetrader.ui.charts.ChartRowViewItem;
import org.eclipsetrader.ui.charts.ChartView;
import org.eclipsetrader.ui.charts.ChartViewItem;
import org.eclipsetrader.ui.charts.IChartEditorListener;
import org.eclipsetrader.ui.charts.IChartObject;
import org.eclipsetrader.ui.internal.UIActivator;
import org.eclipsetrader.ui.internal.charts.DataImportJob;
import org.eclipsetrader.ui.internal.charts.ImportDataPage;
import org.eclipsetrader.ui.internal.charts.Period;
import org.eclipsetrader.ui.internal.charts.PeriodList;

public class ChartViewPart extends ViewPart implements ISaveablePart {

    public static final String VIEW_ID = "org.eclipsetrader.ui.chart"; //$NON-NLS-1$

    public static final String K_VIEWS = "Views"; //$NON-NLS-1$
    public static final String K_URI = "uri"; //$NON-NLS-1$
    public static final String K_TEMPLATE = "template"; //$NON-NLS-1$
    public static final String K_PRIVATE_TEMPLATE = "private-template"; //$NON-NLS-1$

    public static final String K_PERIOD = "period"; //$NON-NLS-1$
    public static final String K_RESOLUTION = "resolution"; //$NON-NLS-1$
    public static final String K_SHOW_TOOLTIPS = "show-tooltips"; //$NON-NLS-1$
    public static final String K_ZOOM_FACTOR = "zoom-factor"; //$NON-NLS-1$
    public static final String K_SHOW_CURRENT_PRICE = "show-current-price"; //$NON-NLS-1$
    public static final String K_SHOW_CURRENT_BOOK = "show-current-book"; //$NON-NLS-1$

    private URI uri;
    private ISecurity security;
    private IChartTemplate template;

    private BaseChartViewer viewer;
    private ChartView view;
    private IHistory history;
    private IHistory subsetHistory;
    private ChartViewDropTarget dropListener;
    private boolean dirty;

    private IDialogSettings dialogSettings;
    private Action cutAction;
    private Action copyAction;
    private Action pasteAction;
    private Action deleteAction;
    private Action propertiesAction;
    private Action zoomOutAction;
    private Action zoomInAction;
    private Action zoomResetAction;
    private Action updateAction;
    private Action periodAllAction;
    private ContributionItem[] periodActions;

    private Action currentPriceLineAction;
    private CurrentPriceLineFactory currentPriceLineFactory;
    private Action currentBookAction;
    private CurrentBookFactory currentBookFactory;

    IMemento memento;
    IPreferenceStore preferenceStore;

    private class ContributionItem extends ActionContributionItem {

        private final Period period;

        public ContributionItem(final Period period) {
            super(new Action(period.getDescription(), Action.AS_RADIO_BUTTON) {

                @Override
                public void run() {
                    setPeriod(period.getPeriod(), period.getResolution());
                }
            });
            this.period = period;
        }

        public Period getPeriod() {
            return period;
        }
    }

    private PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (IPropertyConstants.BARS.equals(evt.getPropertyName())) {
                TimeSpan resolution = TimeSpan.fromString(dialogSettings.get(K_RESOLUTION));
                view.setRootDataSeries(
                        new OHLCDataSeries(security.getName(), subsetHistory.getAdjustedOHLC(), resolution));
                Display.getDefault().asyncExec(new Runnable() {

                    @Override
                    public void run() {
                        if (!viewer.getControl().isDisposed()) {
                            refreshChart();
                        }
                    }
                });
            }
        }
    };

    private IViewChangeListener viewChangeListener = new IViewChangeListener() {

        @Override
        public void viewChanged(ViewEvent event) {
            scheduleLoadJob();
            setDirty();
        }
    };

    private IPropertyChangeListener preferenceChangeListener = new IPropertyChangeListener() {

        @Override
        public void propertyChange(org.eclipse.jface.util.PropertyChangeEvent event) {
            IPreferenceStore preferences = (IPreferenceStore) event.getSource();
            if (UIActivator.PREFS_SHOW_TOOLTIPS.equals(event.getProperty())) {
                viewer.setShowTooltips(preferences.getBoolean(UIActivator.PREFS_SHOW_TOOLTIPS));
            }
            if (UIActivator.PREFS_SHOW_SCALE_TOOLTIPS.equals(event.getProperty())) {
                viewer.setShowScaleTooltips(preferences.getBoolean(UIActivator.PREFS_SHOW_SCALE_TOOLTIPS));
            }
            if (UIActivator.PREFS_CROSSHAIR_ACTIVATION.equals(event.getProperty())) {
                viewer.setCrosshairMode(preferences.getInt(UIActivator.PREFS_CROSSHAIR_ACTIVATION));
            }
            if (UIActivator.PREFS_CROSSHAIR_SUMMARY_TOOLTIP.equals(event.getProperty())) {
                viewer.setDecoratorSummaryTooltips(
                        preferences.getBoolean(UIActivator.PREFS_CROSSHAIR_SUMMARY_TOOLTIP));
            }
            if (UIActivator.PREFS_CHART_PERIODS.equals(event.getProperty())) {
                updatePeriodActions();
            }
        }
    };

    private Action printAction = new Action(Messages.ChartViewPart_PrintAction) {

        @Override
        public void run() {
            PrintDialog dialog = new PrintDialog(getViewSite().getShell(), SWT.NONE);
            PrinterData data = dialog.open();
            if (data == null) {
                return;
            }
            if (data.printToFile) {
                data.fileName = "print.out"; // TODO you probably want to ask the user for a filename //$NON-NLS-1$
            }

            Printer printer = new Printer(data);
            try {
                Rectangle printerBounds = printer.getClientArea();
                Rectangle trimBounds = printer.computeTrim(printerBounds.x, printerBounds.y, printerBounds.width,
                        printerBounds.height);
                System.out.println(printerBounds + ", " + trimBounds); //$NON-NLS-1$

                if (printer.startJob(getPartName())) {
                    viewer.print(printer);
                    printer.endJob();
                }
            } catch (Throwable e) {
                e.printStackTrace();
            } finally {
                printer.dispose();
            }
        }
    };

    public ChartViewPart() {
    }

    /* (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);

        this.memento = memento;
        this.preferenceStore = UIActivator.getDefault().getPreferenceStore();

        try {
            dialogSettings = UIActivator.getDefault().getDialogSettings().getSection(K_VIEWS)
                    .getSection(site.getSecondaryId());
            uri = new URI(dialogSettings.get(K_URI));

            IRepositoryService repositoryService = UIActivator.getDefault().getRepositoryService();
            security = repositoryService.getSecurityFromURI(uri);

            String privateTemplate = dialogSettings.get(K_PRIVATE_TEMPLATE);
            if (privateTemplate != null) {
                template = unmarshal(privateTemplate);
            }

            if (template == null) {
                IPath templatePath = new Path("data"); //$NON-NLS-1$
                if (dialogSettings.get(K_TEMPLATE) != null) {
                    templatePath = templatePath.append(dialogSettings.get(K_TEMPLATE));
                } else {
                    templatePath = templatePath.append("basic-template.xml");
                }
                InputStream stream = FileLocator.openStream(UIActivator.getDefault().getBundle(), templatePath,
                        false);
                template = unmarshal(stream);
            }
        } catch (Exception e) {
            Status status = new Status(IStatus.ERROR, UIActivator.PLUGIN_ID,
                    Messages.ChartViewPart_LoadingErrorMessage + site.getSecondaryId(), e);
            UIActivator.getDefault().getLog().log(status);
        }

        site.setSelectionProvider(new SelectionProvider());

        createActions();
        createPeriodActions();

        IActionBars actionBars = site.getActionBars();

        IMenuManager menuManager = actionBars.getMenuManager();
        menuManager.add(new Separator("periods.top")); //$NON-NLS-1$
        menuManager.add(new Separator("periods")); //$NON-NLS-1$
        menuManager.add(new Separator("periods.bottom")); //$NON-NLS-1$
        menuManager.add(currentPriceLineAction);
        menuManager.add(currentBookAction);

        menuManager.appendToGroup("periods.top", periodAllAction); //$NON-NLS-1$
        if (periodActions != null) {
            for (int i = 0; i < periodActions.length; i++) {
                menuManager.appendToGroup("periods", periodActions[i]);
            }
        }

        IToolBarManager toolBarManager = actionBars.getToolBarManager();
        toolBarManager.add(new Separator("additions")); //$NON-NLS-1$
        toolBarManager.add(updateAction);

        TimeSpan periodTimeSpan = TimeSpan.fromString(dialogSettings.get(K_PERIOD));
        TimeSpan resolutionTimeSpan = TimeSpan.fromString(dialogSettings.get(K_RESOLUTION));
        setPeriodActionSelection(periodTimeSpan, resolutionTimeSpan);

        actionBars.setGlobalActionHandler(cutAction.getId(), cutAction);
        actionBars.setGlobalActionHandler(copyAction.getId(), copyAction);
        actionBars.setGlobalActionHandler(pasteAction.getId(), pasteAction);
        actionBars.setGlobalActionHandler(deleteAction.getId(), deleteAction);

        actionBars.setGlobalActionHandler(ActionFactory.PRINT.getId(), printAction);

        ToolAction toolAction = new ToolAction(Messages.ChartViewPart_LineAction, this,
                "org.eclipsetrader.ui.charts.tools.line");
        actionBars.setGlobalActionHandler(toolAction.getId(), toolAction);
        toolAction = new ToolAction(Messages.ChartViewPart_FiboLineAction, this,
                "org.eclipsetrader.ui.charts.tools.fiboline");
        actionBars.setGlobalActionHandler(toolAction.getId(), toolAction);
        toolAction = new ToolAction(Messages.ChartViewPart_FanLineAction, this,
                "org.eclipsetrader.ui.charts.tools.fanline");
        actionBars.setGlobalActionHandler(toolAction.getId(), toolAction);
        toolAction = new ToolAction(Messages.ChartViewPart_FiboArcAction, this,
                "org.eclipsetrader.ui.charts.tools.fiboarc");
        actionBars.setGlobalActionHandler(toolAction.getId(), toolAction);

        actionBars.setGlobalActionHandler(zoomInAction.getActionDefinitionId(), zoomInAction);
        actionBars.setGlobalActionHandler(zoomOutAction.getActionDefinitionId(), zoomOutAction);
        actionBars.setGlobalActionHandler(zoomResetAction.getActionDefinitionId(), zoomResetAction);
        actionBars.setGlobalActionHandler(propertiesAction.getId(), propertiesAction);
        actionBars.updateActionBars();
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento)
     */
    @Override
    public void saveState(IMemento memento) {
        memento.putInteger(K_ZOOM_FACTOR, viewer.getZoomFactor());

        int[] weights = viewer.getWeights();
        if (weights.length > 1) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < weights.length; i++) {
                if (i != 0) {
                    sb.append(";"); //$NON-NLS-1$
                }
                sb.append(weights[i]);
            }
            memento.putString("weights", sb.toString()); //$NON-NLS-1$
        }

        super.saveState(memento);
    }

    protected void createActions() {
        ISharedImages sharedImages = getViewSite().getWorkbenchWindow().getWorkbench().getSharedImages();

        zoomInAction = new Action(Messages.ChartViewPart_ZoomInAction) {

            @Override
            public void run() {
                int factor = viewer.getZoomFactor();
                viewer.setZoomFactor(factor + 1);
                zoomOutAction.setEnabled(true);
                zoomResetAction.setEnabled(true);
            }
        };
        zoomInAction.setId("zoomIn"); //$NON-NLS-1$
        zoomInAction.setActionDefinitionId("org.eclipsetrader.ui.charts.zoomIn"); //$NON-NLS-1$

        zoomOutAction = new Action(Messages.ChartViewPart_ZoomOutAction) {

            @Override
            public void run() {
                int factor = viewer.getZoomFactor();
                if (factor > 0) {
                    viewer.setZoomFactor(factor - 1);
                }
                zoomOutAction.setEnabled(factor != 1);
                zoomResetAction.setEnabled(factor != 1);
            }
        };
        zoomOutAction.setId("zoomOut"); //$NON-NLS-1$
        zoomOutAction.setActionDefinitionId("org.eclipsetrader.ui.charts.zoomOut"); //$NON-NLS-1$

        zoomResetAction = new Action(Messages.ChartViewPart_NormalSizeAction) {

            @Override
            public void run() {
                viewer.setZoomFactor(0);
                zoomOutAction.setEnabled(false);
                zoomResetAction.setEnabled(false);
            }
        };
        zoomResetAction.setId("zoomReset"); //$NON-NLS-1$
        zoomResetAction.setActionDefinitionId("org.eclipsetrader.ui.charts.zoomReset"); //$NON-NLS-1$

        zoomOutAction.setEnabled(false);
        zoomResetAction.setEnabled(false);

        periodAllAction = new Action(Messages.ChartViewPart_AllPeriodAction, IAction.AS_RADIO_BUTTON) {

            @Override
            public void run() {
                setPeriod(null, TimeSpan.days(1));
            }
        };

        cutAction = new Action(Messages.ChartViewPart_CutAction) {

            @Override
            public void run() {
            }
        };
        cutAction.setId("cut"); //$NON-NLS-1$
        cutAction.setActionDefinitionId("org.eclipse.ui.edit.cut"); //$NON-NLS-1$
        cutAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
        cutAction.setDisabledImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED));
        cutAction.setEnabled(false);

        copyAction = new Action(Messages.ChartViewPart_CopyAction) {

            @Override
            public void run() {
            }
        };
        copyAction.setId("copy"); //$NON-NLS-1$
        copyAction.setActionDefinitionId("org.eclipse.ui.edit.copy"); //$NON-NLS-1$
        copyAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
        copyAction
                .setDisabledImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
        copyAction.setEnabled(false);

        pasteAction = new Action(Messages.ChartViewPart_PasteAction) {

            @Override
            public void run() {
            }
        };
        pasteAction.setId("copy"); //$NON-NLS-1$
        pasteAction.setActionDefinitionId("org.eclipse.ui.edit.paste"); //$NON-NLS-1$
        pasteAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
        pasteAction
                .setDisabledImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED));
        pasteAction.setEnabled(false);

        deleteAction = new Action(Messages.ChartViewPart_DeleteAction) {

            @Override
            public void run() {
                IStructuredSelection selection = (IStructuredSelection) getViewSite().getSelectionProvider()
                        .getSelection();
                if (!selection.isEmpty()) {
                    if (MessageDialog.openConfirm(getViewSite().getShell(), getPartName(),
                            Messages.ChartViewPart_DeleteConfirmMessage)) {
                        ChartViewItem viewItem = (ChartViewItem) selection.getFirstElement();
                        ChartRowViewItem rowViewItem = (ChartRowViewItem) viewItem.getParent();
                        if (rowViewItem.getItemCount() == 1) {
                            rowViewItem.getParentView().removeRow(rowViewItem);
                        } else {
                            rowViewItem.removeChildItem(viewItem);
                        }
                    }
                }
            }
        };
        deleteAction.setId("delete"); //$NON-NLS-1$
        deleteAction.setActionDefinitionId("org.eclipse.ui.edit.delete"); //$NON-NLS-1$
        deleteAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
        deleteAction.setDisabledImageDescriptor(
                sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_DELETE_DISABLED));
        deleteAction.setEnabled(false);

        updateAction = new Action(Messages.ChartViewPart_UpdateAction) {

            @Override
            public void run() {
                doUpdate();
            }
        };
        updateAction.setId("update"); //$NON-NLS-1$
        updateAction.setImageDescriptor(UIActivator.getImageDescriptor("icons/etool16/refresh.gif")); //$NON-NLS-1$
        updateAction.setEnabled(true);

        propertiesAction = new PropertyDialogAction(new SameShellProvider(getViewSite().getShell()),
                getSite().getSelectionProvider()) {

            @Override
            public void run() {
                PreferenceDialog dialog = createDialog();
                if (dialog != null) {
                    if (dialog.open() == Window.OK) {
                        IStructuredSelection selection = (IStructuredSelection) getSite().getSelectionProvider()
                                .getSelection();

                        ChartViewItem viewItem = (ChartViewItem) selection.getFirstElement();
                        ((ChartRowViewItem) viewItem.getParent()).refresh();

                        refreshChart();
                        setDirty();
                    }
                }
            }
        };
        propertiesAction.setId(ActionFactory.PROPERTIES.getId());
        propertiesAction.setActionDefinitionId("org.eclipse.ui.file.properties"); //$NON-NLS-1$
        propertiesAction.setEnabled(false);

        currentPriceLineAction = new Action(Messages.ChartViewPart_ShowCurrentPriceAction, IAction.AS_CHECK_BOX) {

            @Override
            public void run() {
                currentPriceLineFactory.setEnable(isChecked());
                dialogSettings.put(K_SHOW_CURRENT_PRICE, isChecked());
            }
        };

        currentBookAction = new Action(Messages.ChartViewPart_ShowBookAction, IAction.AS_CHECK_BOX) {

            @Override
            public void run() {
                currentBookFactory.setEnable(isChecked());
                dialogSettings.put(K_SHOW_CURRENT_BOOK, isChecked());
            }
        };
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
     */
    @Override
    public void createPartControl(Composite parent) {
        viewer = new BaseChartViewer(parent, SWT.NONE);

        viewer.addSelectionChangedListener(new ISelectionChangedListener() {

            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                handleSelectionChanged((IStructuredSelection) event.getSelection());
                handleActionsEnablement();
            }
        });
        viewer.getEditor().addListener(new IChartEditorListener() {

            @Override
            public void applyEditorValue() {
                refreshChart();
                setDirty();
            }

            @Override
            public void cancelEditor() {
            }
        });

        Transfer[] transferTypes = new Transfer[] { ChartObjectFactoryTransfer.getInstance(), };
        DropTarget dropTarget = new DropTarget(viewer.getControl(), DND.DROP_COPY | DND.DROP_MOVE);
        dropTarget.setTransfer(transferTypes);
        dropTarget.addDropListener(dropListener = new ChartViewDropTarget(viewer));

        viewer.setShowTooltips(preferenceStore.getBoolean(UIActivator.PREFS_SHOW_TOOLTIPS));
        viewer.setShowScaleTooltips(preferenceStore.getBoolean(UIActivator.PREFS_SHOW_SCALE_TOOLTIPS));
        viewer.setCrosshairMode(preferenceStore.getInt(UIActivator.PREFS_CROSSHAIR_ACTIVATION));
        viewer.setDecoratorSummaryTooltips(preferenceStore.getBoolean(UIActivator.PREFS_CROSSHAIR_SUMMARY_TOOLTIP));
        preferenceStore.addPropertyChangeListener(preferenceChangeListener);

        if (memento != null) {
            if (memento.getString(K_ZOOM_FACTOR) != null) {
                int factor = memento.getInteger(K_ZOOM_FACTOR);
                viewer.setZoomFactor(factor);
                zoomOutAction.setEnabled(factor != 0);
                zoomResetAction.setEnabled(factor != 0);
            }
        }

        createContextMenu();

        currentPriceLineFactory = new CurrentPriceLineFactory();
        currentPriceLineFactory.setSecurity(security);
        currentPriceLineFactory.setEnable(dialogSettings.getBoolean(K_SHOW_CURRENT_PRICE));
        currentPriceLineAction.setChecked(dialogSettings.getBoolean(K_SHOW_CURRENT_PRICE));

        currentBookFactory = new CurrentBookFactory();
        currentBookFactory.setSecurity(security);
        currentBookFactory.setEnable(dialogSettings.getBoolean(K_SHOW_CURRENT_BOOK));
        currentBookAction.setChecked(dialogSettings.getBoolean(K_SHOW_CURRENT_BOOK));

        if (security != null && template != null) {
            setPartName(NLS.bind("{0} - {1}", new Object[] { //$NON-NLS-1$
                    security.getName(), template.getName(), }));

            view = new ChartView(template);

            ChartRowViewItem rowItem = (ChartRowViewItem) view.getItems()[0];

            ChartViewItem viewItem = new ChartViewItem(rowItem, currentPriceLineFactory);
            rowItem.addChildItem(0, viewItem);

            viewItem = new ChartViewItem(rowItem, currentBookFactory);
            rowItem.addChildItem(0, viewItem);

            view.addViewChangeListener(viewChangeListener);

            scheduleLoadJob();
        }
    }

    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("top")); //$NON-NLS-1$
                menuManager.add(cutAction);
                menuManager.add(copyAction);
                menuManager.add(pasteAction);
                menuManager.add(new Separator());
                menuManager.add(deleteAction);
                menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
                menuManager.add(propertiesAction);
            }
        });
        viewer.getControl().setMenu(menuMgr.createContextMenu(viewer.getControl()));
        getSite().registerContextMenu(menuMgr, getSite().getSelectionProvider());
    }

    void scheduleLoadJob() {
        final Display display = viewer.getControl().getDisplay();

        if (subsetHistory != null) {
            PropertyChangeSupport propertyChangeSupport = (PropertyChangeSupport) subsetHistory
                    .getAdapter(PropertyChangeSupport.class);
            if (propertyChangeSupport != null) {
                propertyChangeSupport.removePropertyChangeListener(propertyChangeListener);
            }
        }

        ChartLoadJob job = new ChartLoadJob(security);
        job.addJobChangeListener(new JobChangeAdapter() {

            @Override
            public void done(IJobChangeEvent event) {
                final ChartLoadJob job = (ChartLoadJob) event.getJob();

                history = job.getHistory();
                subsetHistory = job.getSubsetHistory();
                view.setRootDataSeries(new OHLCDataSeries(security.getName(), subsetHistory.getAdjustedOHLC(),
                        job.getResolutionTimeSpan()));

                display.asyncExec(new Runnable() {

                    @Override
                    public void run() {
                        if (viewer.getControl().isDisposed()) {
                            return;
                        }

                        if (memento == null) {
                            memento = XMLMemento.createWriteRoot("root"); //$NON-NLS-1$
                        }
                        saveState(memento);

                        TimeSpan resolutionTimeSpan = TimeSpan.fromString(dialogSettings.get(K_RESOLUTION));
                        if (resolutionTimeSpan == null) {
                            resolutionTimeSpan = TimeSpan.days(1);
                        }
                        viewer.setResolutionTimeSpan(resolutionTimeSpan);

                        dropListener.setView(view);

                        PropertyChangeSupport propertyChangeSupport = (PropertyChangeSupport) subsetHistory
                                .getAdapter(PropertyChangeSupport.class);
                        if (propertyChangeSupport != null) {
                            propertyChangeSupport.addPropertyChangeListener(propertyChangeListener);
                        }

                        refreshChart();
                    }
                });
            }
        });
        job.setTimeSpan(TimeSpan.fromString(dialogSettings.get(K_PERIOD)));
        job.setResolutionTimeSpan(TimeSpan.fromString(dialogSettings.get(K_RESOLUTION)));
        job.setName(Messages.ChartViewPart_LoadingText + getPartName());
        job.setUser(true);
        job.schedule();
    }

    /* (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() {
        view.removeViewChangeListener(viewChangeListener);

        if (subsetHistory != null) {
            PropertyChangeSupport propertyChangeSupport = (PropertyChangeSupport) subsetHistory
                    .getAdapter(PropertyChangeSupport.class);
            if (propertyChangeSupport != null) {
                propertyChangeSupport.removePropertyChangeListener(propertyChangeListener);
            }
        }

        if (UIActivator.getDefault() != null) {
            IPreferenceStore preferences = UIActivator.getDefault().getPreferenceStore();
            preferences.removePropertyChangeListener(preferenceChangeListener);
        }

        super.dispose();
    }

    protected void handleSelectionChanged(IStructuredSelection selection) {
        if (selection.size() != 1 || !(selection.getFirstElement() instanceof IChartObject)) {
            getViewSite().getSelectionProvider().setSelection(StructuredSelection.EMPTY);
            return;
        }
        ChartViewItemFinder finder = new ChartViewItemFinder((IChartObject) selection.getFirstElement());
        view.accept(finder);
        if (finder.getViewItem() == null) {
            getViewSite().getSelectionProvider().setSelection(new StructuredSelection(view));
        } else {
            getViewSite().getSelectionProvider().setSelection(new StructuredSelection(finder.getViewItem()));
        }
    }

    protected void handleActionsEnablement() {
        IStructuredSelection selection = (IStructuredSelection) getViewSite().getSelectionProvider().getSelection();
        IViewItem viewItem = (IViewItem) selection.getFirstElement();

        cutAction.setEnabled(
                !selection.isEmpty() && viewItem != null && viewItem.getAdapter(MainChartFactory.class) == null);
        copyAction.setEnabled(
                !selection.isEmpty() && viewItem != null && viewItem.getAdapter(MainChartFactory.class) == null);

        deleteAction.setEnabled(
                !selection.isEmpty() && viewItem != null && viewItem.getAdapter(MainChartFactory.class) == null);

        propertiesAction.setEnabled(!selection.isEmpty());
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public void doSave(IProgressMonitor monitor) {
        try {
            String privateTemplate = marshal(view.getTemplate());
            dialogSettings.put(K_PRIVATE_TEMPLATE, privateTemplate);
            clearDirty();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.ISaveablePart#doSaveAs()
     */
    @Override
    public void doSaveAs() {
    }

    protected void setDirty() {
        if (!dirty) {
            dirty = true;
            firePropertyChange(PROP_DIRTY);
        }
    }

    protected void clearDirty() {
        if (dirty) {
            dirty = false;
            firePropertyChange(PROP_DIRTY);
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.ISaveablePart#isDirty()
     */
    @Override
    public boolean isDirty() {
        return dirty;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
     */
    @Override
    public boolean isSaveAsAllowed() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.ISaveablePart#isSaveOnCloseNeeded()
     */
    @Override
    public boolean isSaveOnCloseNeeded() {
        return dirty;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object getAdapter(Class adapter) {
        if (adapter.isAssignableFrom(BaseChartViewer.class)) {
            return viewer;
        }
        if (adapter.isAssignableFrom(ChartCanvas.class)) {
            return viewer.getSelectedChartCanvas();
        }
        if (adapter.isAssignableFrom(ChartView.class)) {
            return view;
        }
        if (adapter.isAssignableFrom(IChartTemplate.class)) {
            return template;
        }
        if (adapter.isAssignableFrom(ISecurity.class)) {
            return security;
        }
        if (adapter.isAssignableFrom(IDialogSettings.class)) {
            return dialogSettings;
        }
        return super.getAdapter(adapter);
    }

    private String marshal(IChartTemplate object) throws Exception {
        StringWriter string = new StringWriter();
        JAXBContext jaxbContext = JAXBContext.newInstance(ChartTemplate.class);
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); //$NON-NLS-1$
        marshaller.marshal(object, string);
        return string.toString();
    }

    private ChartTemplate unmarshal(String string) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(ChartTemplate.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        return (ChartTemplate) unmarshaller.unmarshal(new StringReader(string));
    }

    private ChartTemplate unmarshal(InputStream stream) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(ChartTemplate.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        return (ChartTemplate) unmarshaller.unmarshal(stream);
    }

    protected void refreshChart() {
        BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {

            @Override
            public void run() {
                ChartRowViewItem[] rowViewItem = (ChartRowViewItem[]) view.getAdapter(ChartRowViewItem[].class);
                if (rowViewItem != null) {
                    IChartObject[][] input = new IChartObject[rowViewItem.length][];
                    for (int i = 0; i < input.length; i++) {
                        input[i] = (IChartObject[]) rowViewItem[i].getAdapter(IChartObject[].class);
                    }
                    viewer.setInput(input);

                    if (memento != null && memento.getString("weights") != null) { //$NON-NLS-1$
                        String[] s = memento.getString("weights").split(";"); //$NON-NLS-1$ //$NON-NLS-2$
                        int[] weights = viewer.getWeights();
                        for (int i = 0; i < weights.length && i < s.length; i++) {
                            weights[i] = Integer.valueOf(s[i]);
                        }
                        viewer.setWeights(weights);
                    }
                }
            }
        });
    }

    public void setPeriod(TimeSpan period, TimeSpan resolution) {
        dialogSettings.put(K_PERIOD, period != null ? period.toString() : (String) null);
        dialogSettings.put(K_RESOLUTION, resolution != null ? resolution.toString() : (String) null);

        periodAllAction.setChecked(period == null);
        setPeriodActionSelection(period, resolution);

        scheduleLoadJob();
    }

    protected void doUpdate() {
        TimeSpan[] aggregation = new TimeSpan[] { TimeSpan.days(1), TimeSpan.minutes(1), };

        IDialogSettings dialogSettings = UIActivator.getDefault().getDialogSettings()
                .getSection(ImportDataPage.class.getName());
        if (dialogSettings != null) {
            String[] s = dialogSettings.getArray("AGGREGATION");
            if (s != null && s.length != 0) {
                aggregation = new TimeSpan[s.length];
                for (int i = 0; i < aggregation.length; i++) {
                    aggregation[i] = TimeSpan.fromString(s[i]);
                }
            }
        }

        DataImportJob job = new DataImportJob(security, DataImportJob.INCREMENTAL, null, null, aggregation);
        job.setUser(true);
        job.schedule();
    }

    protected void updatePeriodActions() {
        IActionBars actionBars = getViewSite().getActionBars();

        IMenuManager menuManager = actionBars.getMenuManager();
        if (periodActions != null) {
            for (int i = 0; i < periodActions.length; i++) {
                menuManager.remove(periodActions[i]);
                periodActions[i].dispose();
            }
            periodActions = null;
        }

        createPeriodActions();

        if (periodActions != null) {
            for (int i = 0; i < periodActions.length; i++) {
                menuManager.appendToGroup("periods", periodActions[i]);
            }
        }

        TimeSpan periodTimeSpan = TimeSpan.fromString(dialogSettings.get(K_PERIOD));
        TimeSpan resolutionTimeSpan = TimeSpan.fromString(dialogSettings.get(K_RESOLUTION));
        setPeriodActionSelection(periodTimeSpan, resolutionTimeSpan);

        actionBars.updateActionBars();
    }

    public void createPeriodActions() {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(PeriodList.class);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            StringReader stream = new StringReader(
                    UIActivator.getDefault().getPreferenceStore().getString(UIActivator.PREFS_CHART_PERIODS));

            PeriodList list = (PeriodList) unmarshaller.unmarshal(stream);
            Collections.sort(list, new Comparator<Period>() {

                @Override
                public int compare(Period o1, Period o2) {
                    if (o1.getPeriod().higherThan(o2.getPeriod())) {
                        return -1;
                    }
                    if (o2.getPeriod().higherThan(o1.getPeriod())) {
                        return 1;
                    }
                    return 0;
                }
            });

            periodActions = new ContributionItem[list.size()];
            for (int i = 0; i < periodActions.length; i++) {
                periodActions[i] = new ContributionItem(list.get(i));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setPeriodActionSelection(TimeSpan period, TimeSpan resolution) {
        if (periodActions != null) {
            for (int i = 0; i < periodActions.length; i++) {
                periodActions[i].getAction().setChecked(periodActions[i].getPeriod().equalsTo(period, resolution));
            }
        }
    }
}