org.eclipse.birt.chart.ui.swt.wizard.TaskFormatChart.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.birt.chart.ui.swt.wizard.TaskFormatChart.java

Source

/*******************************************************************************
 * Copyright (c) 2005, 2007 Actuate Corporation.
 * 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:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.chart.ui.swt.wizard;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.eclipse.birt.chart.exception.ChartException;
import org.eclipse.birt.chart.model.Chart;
import org.eclipse.birt.chart.model.ChartWithAxes;
import org.eclipse.birt.chart.model.ChartWithoutAxes;
import org.eclipse.birt.chart.model.DialChart;
import org.eclipse.birt.chart.model.IChartObject;
import org.eclipse.birt.chart.model.attribute.ChartDimension;
import org.eclipse.birt.chart.ui.extension.i18n.Messages;
import org.eclipse.birt.chart.ui.swt.ChartPreviewPainter;
import org.eclipse.birt.chart.ui.swt.interfaces.IChartPreviewPainter;
import org.eclipse.birt.chart.ui.swt.interfaces.IDataServiceProvider;
import org.eclipse.birt.chart.ui.swt.interfaces.IRegisteredSheetEntry;
import org.eclipse.birt.chart.ui.swt.interfaces.IRegisteredSubtaskEntry;
import org.eclipse.birt.chart.ui.swt.interfaces.ITaskChangeListener;
import org.eclipse.birt.chart.ui.swt.interfaces.ITaskPreviewable;
import org.eclipse.birt.chart.ui.swt.interfaces.IUIManager;
import org.eclipse.birt.chart.ui.swt.type.PieChart;
import org.eclipse.birt.chart.ui.swt.wizard.preview.ChartLivePreviewThread;
import org.eclipse.birt.chart.ui.swt.wizard.preview.LivePreviewTask;
import org.eclipse.birt.chart.ui.util.ChartUIConstants;
import org.eclipse.birt.chart.ui.util.ChartUIUtil;
import org.eclipse.birt.chart.ui.util.UIHelper;
import org.eclipse.birt.core.ui.frameworks.taskwizard.TreeCompoundTask;
import org.eclipse.birt.core.ui.frameworks.taskwizard.WizardBase;
import org.eclipse.birt.core.ui.frameworks.taskwizard.composites.NavTree;
import org.eclipse.birt.core.ui.frameworks.taskwizard.interfaces.ISubtaskSheet;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TreeItem;

/**
 * Task sheet for formatting chart
 */

public class TaskFormatChart extends TreeCompoundTask implements IUIManager, ITaskChangeListener, ITaskPreviewable {

    protected IChartPreviewPainter previewPainter = null;

    private Canvas previewCanvas;

    private Label lblNodeTitle;

    // registered collections of sheets.
    // Key:collectionName; Value:nodePath array
    private Hashtable<String, String[]> htSheetCollections = null;

    // visible UI Sheets (Order IS important)
    // Key: nodePath; Value: subtask or Vector
    protected LinkedHashMap<String, Object> htVisibleSheets = null;

    protected int iBaseSeriesCount = 0;

    protected int iOrthogonalSeriesCount = 0;

    protected int iBaseAxisCount = 0;

    protected int iOrthogonalAxisCount = 0;

    protected int iAncillaryAxisCount = 0;

    protected static final String ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITH_AXES = "OrthogonalSeriesSheetsCWA"; //$NON-NLS-1$

    protected static final String BASE_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES = "BaseSeriesSheetsCWOA"; //$NON-NLS-1$

    protected static final String ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES = "OrthogonalSeriesSheetsCWOA"; //$NON-NLS-1$

    protected static final String BASE_AXIS_SHEET_COLLECTION = "BaseAxisSheets"; //$NON-NLS-1$

    protected static final String ORTHOGONAL_AXIS_SHEET_COLLECTION = "OrthogonalAxisSheets"; //$NON-NLS-1$

    protected static final String ANCILLARY_AXIS_SHEET_COLLECTION = "AncillaryAxisSheets"; //$NON-NLS-1$

    protected static final String DIAL_SERIES_SHEET_COLLECTION = "NeedleSheets"; //$NON-NLS-1$

    protected Map<String, String[]> subtasksRegistry = new HashMap<String, String[]>(7);

    private IRegisteredSubtaskEntry rootSubtaskEntry = null;

    protected int subtaskHeightHint = 500;
    protected int subtaskWidthHint = SWT.DEFAULT;

    public TaskFormatChart() {
        super(Messages.getString("TaskFormatChart.TaskExp"), true); //$NON-NLS-1$
        setDescription(Messages.getString("TaskFormatChart.Task.Description")); //$NON-NLS-1$   
        registerSubtasks();
    }

    protected void registerSubtasks() {
        subtasksRegistry.put(BASE_AXIS_SHEET_COLLECTION, new String[] { "Chart.Axis", "Chart.Axis.X Axis"//$NON-NLS-1$ //$NON-NLS-2$
        });
        subtasksRegistry.put(ORTHOGONAL_AXIS_SHEET_COLLECTION, new String[] { "Chart.Axis.Y Axis" //$NON-NLS-1$
        });
        subtasksRegistry.put(ANCILLARY_AXIS_SHEET_COLLECTION, new String[] { "Chart.Axis.Z Axis" //$NON-NLS-1$
        });
        subtasksRegistry.put(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITH_AXES,
                new String[] { "Series.Y Series" //$NON-NLS-1$
                });
        subtasksRegistry.put(BASE_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES,
                new String[] { "Series.Category Series" //$NON-NLS-1$
                });
        subtasksRegistry.put(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES,
                new String[] { "Series.Value Series" //$NON-NLS-1$
                });
        subtasksRegistry.put(DIAL_SERIES_SHEET_COLLECTION, new String[] { "Series.Value Series.Needle" //$NON-NLS-1$
        });
    }

    private Collection<IRegisteredSubtaskEntry> getRegisteredSubtasks() {
        // Gets all registered subtasks from extension id.
        Collection<IRegisteredSubtaskEntry> cRegisteredEntries = new ArrayList<IRegisteredSubtaskEntry>();
        Class<?> clazz = this.getClass();
        if (rootSubtaskEntry != null) {
            cRegisteredEntries.add(rootSubtaskEntry);
        }
        while (clazz != TreeCompoundTask.class) {
            Collection<IRegisteredSubtaskEntry> cSheets = ChartUIExtensionsImpl.instance()
                    .getUISheetExtensions(clazz.getSimpleName());
            if (cSheets != null && cSheets.size() > 0) {
                for (IRegisteredSubtaskEntry subtaskEntry : cSheets) {
                    if (rootSubtaskEntry != null
                            && clazz.getSimpleName().equals(TaskFormatChart.class.getSimpleName())) {
                        cRegisteredEntries.add(
                                new DefaultRegisteredSubtaskEntryImpl(String.valueOf(subtaskEntry.getNodeIndex()),
                                        getNodePathWithRoot(subtaskEntry.getNodePath()),
                                        subtaskEntry.getDisplayName(), subtaskEntry.getSheet()));
                    } else {
                        cRegisteredEntries.add(subtaskEntry);
                    }
                }
                // If current id has registered subtasks, return them.
                return cRegisteredEntries;
            }
            clazz = clazz.getSuperclass();
        }
        return cRegisteredEntries;
    }

    private String getNodePathWithRoot(String nodePath) {
        if (rootSubtaskEntry != null) {
            String prefix = rootSubtaskEntry.getNodePath() + "."; //$NON-NLS-1$
            if (!nodePath.startsWith(prefix)) {
                return prefix + nodePath;
            }
        }
        return nodePath;
    }

    /**
     * Sets the root node for all format chart nodes
     * 
     * @param rootSubtaskEntry
     */
    protected void setRootNode(IRegisteredSubtaskEntry rootSubtaskEntry) {
        this.rootSubtaskEntry = rootSubtaskEntry;
    }

    protected void populateSubtasks() {
        super.populateSubtasks();

        htVisibleSheets = new LinkedHashMap<String, Object>(12);
        htSheetCollections = new Hashtable<String, String[]>();

        // Get collection of registered Sheets
        Iterator<IRegisteredSubtaskEntry> iterEntries = getRegisteredSubtasks().iterator();

        // Vector to be used to build a sorted list of registered sheets (sorted
        // on provided node index)
        Vector<IRegisteredSubtaskEntry> vSortedEntries = new Vector<IRegisteredSubtaskEntry>();
        while (iterEntries.hasNext()) {
            IRegisteredSubtaskEntry entry = iterEntries.next();
            if (vSortedEntries.isEmpty()) {
                vSortedEntries.add(entry);
            } else {
                // Find location where the new entry needs to be inserted
                int iNewIndex = entry.getNodeIndex();

                // Try the last entry
                if ((vSortedEntries.get(vSortedEntries.size() - 1)).getNodeIndex() <= iNewIndex) {
                    vSortedEntries.add(entry);
                } else if ((vSortedEntries.get(0)).getNodeIndex() > iNewIndex)
                // Try the first entry
                {
                    vSortedEntries.add(0, entry);
                } else {
                    vSortedEntries = addEntrySorted(vSortedEntries, entry, 0, vSortedEntries.size() - 1);
                }
            }
        }

        for (int i = 0; i < vSortedEntries.size(); i++) {
            IRegisteredSubtaskEntry entry = vSortedEntries.get(i);
            ISubtaskSheet sheet = entry.getSheet();

            String sNodePath = entry.getNodePath();
            sheet.setParentTask(this);
            sheet.setNodePath(sNodePath);

            // Provide customization for subtask visibility
            if (!checkSubtaskVisibility(sheet)) {
                continue;
            }

            // Initially ALL registered sheets are visible
            htVisibleSheets.put(sNodePath, sheet);
            sheet.setTitle(entry.getDisplayName());

            addSubtask(sNodePath, sheet);
        }

        if (getCurrentModelState() != null) {
            initialize(getCurrentModelState());
        }
    }

    /**
     * Checks if current subtask is visible.
     * 
     * @param subtask
     *            subtask
     * @return visible or not
     */
    protected boolean checkSubtaskVisibility(ISubtaskSheet subtask) {
        // Always visible in OS chart builder.
        return true;
    }

    /**
     * Returns if tree view can support multiple value series
     * 
     * @return
     */
    protected boolean isMultipleValueSeriesAllowed() {
        // OS chart builder supports UI for multiple value series.
        return true;
    }

    public void updateTreeItem() {
        super.updateTreeItem();

        getNavigatorTree().removeAll();
        Iterator<String> itKeys = htVisibleSheets.keySet().iterator();
        while (itKeys.hasNext()) {
            String sKey = itKeys.next();
            Object oVal = htVisibleSheets.get(sKey);
            if (oVal instanceof Vector<?>) {
                Vector<ISubtaskSheet> vector = (Vector<ISubtaskSheet>) oVal;
                for (int i = 0; i < vector.size(); i++) {
                    String sSuffix = ""; //$NON-NLS-1$
                    if (vector.size() > 1) {
                        sSuffix = INDEX_SEPARATOR + String.valueOf(i + 1);
                    }
                    // // If parent is dynamic as well
                    // String sParentKey = sKey.substring( 0,
                    // sKey.lastIndexOf( NavTree.SEPARATOR ) );
                    // Object oParentVal = htVisibleSheets.get( sParentKey );
                    // if ( oParentVal != null && oParentVal instanceof Vector )
                    // {
                    // getNavigatorTree( ).addNode( sParentKey
                    // + sSuffix
                    // + NavTree.SEPARATOR
                    // + sKey.substring( sKey.lastIndexOf( NavTree.SEPARATOR ) )
                    // + sSuffix );
                    // }
                    // else
                    {
                        String displayName = vector.get(i).getTitle();
                        if (displayName != null && displayName.trim().length() > 0) {
                            getNavigatorTree().addNode(sKey + sSuffix, displayName + sSuffix);
                        } else {
                            getNavigatorTree().addNode(sKey + sSuffix);
                        }
                    }
                }
            } else {
                getNavigatorTree().addNode(sKey, ((ISubtaskSheet) oVal).getTitle());
            }
        }
    }

    private Vector<IRegisteredSubtaskEntry> addEntrySorted(Vector<IRegisteredSubtaskEntry> vSortedEntries,
            IRegisteredSubtaskEntry entry, int iStart, int iEnd) {
        int iNewIndex = entry.getNodeIndex();
        if (iStart == iEnd) {
            if (((IRegisteredSheetEntry) vSortedEntries.get(iStart)).getNodeIndex() > iNewIndex) {
                vSortedEntries.add(iStart, entry);
            } else {
                vSortedEntries.add(iEnd + 1, entry);
            }
        } else if ((iEnd - iStart) == 1) {
            vSortedEntries.add(iEnd, entry);
        } else {
            if ((vSortedEntries.get(iStart)).getNodeIndex() == iNewIndex) {
                vSortedEntries.add(iStart + 1, entry);
            } else {
                int iHalfwayPoint = (iEnd - iStart) / 2;
                if ((vSortedEntries.get(iStart + iHalfwayPoint)).getNodeIndex() > iNewIndex) {
                    addEntrySorted(vSortedEntries, entry, iStart, (iStart + iHalfwayPoint));
                } else {
                    addEntrySorted(vSortedEntries, entry, (iStart + iHalfwayPoint), iEnd);
                }
            }
        }
        return vSortedEntries;
    }

    public boolean registerSheetCollection(String sCollection, String[] saNodePaths) {
        if (saNodePaths == null) {
            return false;
        }
        try {
            if (rootSubtaskEntry != null) {
                String[] newNodePaths = new String[saNodePaths.length];
                for (int i = 0; i < saNodePaths.length; i++) {
                    newNodePaths[i] = getNodePathWithRoot(saNodePaths[i]);
                }
                htSheetCollections.put(sCollection, newNodePaths);
            } else {
                htSheetCollections.put(sCollection, saNodePaths);
            }

            return true;
        } catch (Throwable e) {
            return false;
        }
    }

    protected boolean registerSheetCollection(String sCollection) {
        return registerSheetCollection(sCollection, subtasksRegistry.get(sCollection));
    }

    public String[] getRegisteredCollectionValue(String sCollection) {
        return htSheetCollections.get(sCollection);
    }

    public boolean addCollectionInstance(String sCollection) {
        if (!htSheetCollections.containsKey(sCollection)) {
            return false;
        }
        String[] saNodes = htSheetCollections.get(sCollection);
        for (int iN = 0; iN < saNodes.length; iN++) {
            addVisibleSubtask(saNodes[iN]);
        }
        return true;
    }

    private void addVisibleSubtask(String sNodeName) {
        Vector<ISubtaskSheet> vSheets = new Vector<ISubtaskSheet>();
        // check if node exists in tree
        if (htVisibleSheets.containsKey(sNodeName)) {
            Object oSheets = htVisibleSheets.get(sNodeName);
            if (oSheets instanceof Vector<?>) {
                vSheets = (Vector<ISubtaskSheet>) oSheets;
            } else if (oSheets instanceof ISubtaskSheet) {
                vSheets.add((ISubtaskSheet) oSheets);
            } else {
                return;
            }
            vSheets.add(getSubtask(sNodeName));
            htVisibleSheets.put(sNodeName, vSheets);
        } else {
            if (containSubtask(sNodeName)) {
                vSheets.add(getSubtask(sNodeName));
                htVisibleSheets.put(sNodeName, vSheets);
            }
        }
    }

    private void removeVisibleTask(String sNodeName) {
        Vector<ISubtaskSheet> vSheets = new Vector<ISubtaskSheet>();
        // check if node exists in tree
        if (htVisibleSheets.containsKey(sNodeName)) {
            Object oSheets = htVisibleSheets.get(sNodeName);
            if (oSheets instanceof Vector<?>) {
                vSheets = (Vector<ISubtaskSheet>) oSheets;
            } else if (oSheets instanceof ISubtaskSheet) {
                vSheets.add((ISubtaskSheet) oSheets);
            } else {
                return;
            }

            int iLast = vSheets.lastIndexOf(getSubtask(sNodeName));
            vSheets.remove(iLast);
            htVisibleSheets.put(sNodeName, vSheets);
        } else {
            if (containSubtask(sNodeName)) {
                int iLast = vSheets.lastIndexOf(getSubtask(sNodeName));
                vSheets.remove(iLast);
                htVisibleSheets.put(sNodeName, vSheets);
            }
        }
    }

    public boolean removeCollectionInstance(String sCollection) {
        if (!htSheetCollections.containsKey(sCollection)) {
            return false;
        }
        String[] saNodes = htSheetCollections.get(sCollection);
        for (int iN = 0; iN < saNodes.length; iN++) {
            removeVisibleTask(saNodes[iN]);
        }
        return true;
    }

    public Chart getCurrentModelState() {
        if (getContext() == null) {
            return null;
        }
        return ((ChartWizardContext) getContext()).getModel();
    }

    public void createControl(Composite parent) {
        // Initialize all components.
        initControl(parent);

        if (previewPainter == null) {
            // Invoke this only once
            previewPainter = createPreviewPainter();
        }
        if (!isSutaskPreviewable(getCurrentSubtask())) {
            // If current subtask supports preview by itself, do not preview as
            // a whole page
            doPreview();
        }
    }

    private void initDetailHeader(Composite parent) {

        lblNodeTitle = new Label(parent, SWT.NONE);
        {
            GridData gd = new GridData(GridData.FILL_HORIZONTAL);
            lblNodeTitle.setLayoutData(gd);

            lblNodeTitle.setFont(JFaceResources.getBannerFont());
        }

        Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
        {
            GridData gd = new GridData(GridData.FILL_HORIZONTAL);
            separator.setLayoutData(gd);
        }
    }

    /**
     * Initialize components in these shell.
     * 
     * @param parent
     *            parent composite.
     */
    private void initControl(Composite parent) {
        // Initialize chart types first.
        ChartUIUtil.populateTypeTable(getContext());

        if (topControl == null || topControl.isDisposed()) {
            // 1. Create top level composite of the shell.
            topControl = new Composite(parent, SWT.NONE);
            {
                GridLayout layout = new GridLayout(2, false);
                layout.marginHeight = 0;
                layout.marginWidth = 0;
                layout.horizontalSpacing = 0;
                topControl.setLayout(layout);
                GridData gridData = new GridData();
                gridData.horizontalAlignment = SWT.FILL;
                gridData.verticalAlignment = SWT.FILL;
                topControl.setLayoutData(gridData);
            }

            // 2. Create left navigator tree.
            navTree = new NavTree(topControl, SWT.BORDER);
            {
                final GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.FILL_VERTICAL);
                gridData.widthHint = 127;
                navTree.setLayoutData(gridData);
                navTree.addListener(SWT.Selection, new Listener() {

                    public void handleEvent(Event event) {
                        switchToTreeItem((TreeItem) event.item);
                    }
                });
            }

            // 3. Create right sash form, it contains chart preview canvas and
            // detail sub-task sheet.
            SashForm foRightSashForm = new SashForm(topControl, SWT.VERTICAL) {

                @Override
                public Control[] getChildren() {
                    Control[] children = super.getChildren();
                    List<Control> visibleChildren = new ArrayList<Control>();
                    for (Control child : children) {
                        if (child.isVisible()) {
                            visibleChildren.add(child);
                        }
                    }
                    if (visibleChildren.size() == 0 || visibleChildren.size() == children.length) {
                        // In first loading, no visible controls
                        return children;
                    }
                    return visibleChildren.toArray(new Control[visibleChildren.size()]);
                }
            };
            {
                foRightSashForm.SASH_WIDTH = 1;
                foRightSashForm.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));

                GridLayout layout = new GridLayout();
                foRightSashForm.setLayout(layout);
                GridData gridData = new GridData(GridData.FILL_BOTH);
                gridData.heightHint = subtaskHeightHint;
                gridData.widthHint = subtaskWidthHint;
                foRightSashForm.setLayoutData(gridData);
            }
            // 3.1 Create preview canvas and add to right sash form.
            createContainer(foRightSashForm);

            // 3.2 Create detail sheet composite and add to right sash form.
            createDetailComposite(foRightSashForm);
        }

        updateTree();
        switchToDefaultItem();
    }

    /**
     * Create detail sheet composite.
     * 
     * @param parent
     *            parent composite.
     */
    private void createDetailComposite(Composite parent) {
        Composite detailComposite = new Composite(parent, SWT.NONE);
        {
            GridLayout layout = new GridLayout();
            detailComposite.setLayout(layout);
            GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
            detailComposite.setLayoutData(gridData);
        }

        initDetailHeader(detailComposite);

        createSubDetailComposite(detailComposite, !isSutaskPreviewable(getCurrentSubtask()));
    }

    /**
     * Create scrolled composite which contains detail sub-task sheet.
     * 
     * @param detailComposite
     *            parent composite.
     * @param bScrolled
     *            indicate if scrolled composite is needed
     */
    private void createSubDetailComposite(Composite detailComposite, boolean bScrolled) {
        if (!bScrolled) {
            // If current subtask can preview, do not set scrolled composite for
            // it.
            cmpSubtaskContainer = new Composite(detailComposite, SWT.NONE);
            GridLayout layout = new GridLayout();
            cmpSubtaskContainer.setLayout(layout);
            GridData gridData = new GridData(GridData.FILL_BOTH);
            cmpSubtaskContainer.setLayoutData(gridData);
        } else {
            ScrolledComposite foScrolledDetailComposite = new ScrolledComposite(detailComposite,
                    SWT.V_SCROLL | SWT.H_SCROLL);
            {
                GridLayout layout = new GridLayout();
                foScrolledDetailComposite.setLayout(layout);
                GridData gridData = new GridData(GridData.FILL_BOTH);
                foScrolledDetailComposite.setLayoutData(gridData);

                foScrolledDetailComposite.setExpandHorizontal(true);
                foScrolledDetailComposite.setExpandVertical(true);
            }

            cmpSubtaskContainer = new Composite(foScrolledDetailComposite, SWT.NONE);
            {
                GridLayout layout = new GridLayout();
                cmpSubtaskContainer.setLayout(layout);
                GridData gridData = new GridData(GridData.FILL_BOTH);
                cmpSubtaskContainer.setLayoutData(gridData);
            }

            foScrolledDetailComposite.setContent(cmpSubtaskContainer);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.birt.core.ui.frameworks.taskwizard.TreeCompoundTask#switchTo
     * (java.lang.String, boolean)
     */
    protected void switchTo(String sSubtaskPath, boolean needSelection) {
        boolean bPreviewableOld = isSutaskPreviewable(getCurrentSubtask());
        boolean bPreviewableNew = isSutaskPreviewable(getSubtask(sSubtaskPath));

        if (bPreviewableOld != bPreviewableNew) {
            Composite cmpParent = cmpSubtaskContainer.getParent();

            // Update preview canvas and switch between scrolled composite and
            // normal composite
            previewCanvas.getParent().getParent().setVisible(!bPreviewableNew);
            previewCanvas.getParent().getParent().getParent().layout();
            if (!bPreviewableNew) {
                // Re-render preview if previous preview is standalone
                doPreview();

                cmpSubtaskContainer.dispose();
            } else {
                cmpParent = cmpParent.getParent();
                cmpSubtaskContainer.getParent().dispose();
            }
            createSubDetailComposite(cmpParent, !bPreviewableNew);
        }

        super.switchTo(sSubtaskPath, needSelection);

        if (!bPreviewableNew) {
            // Compute minimum size for scrolled composite to let correct scroll
            // behavior.
            Point childSize = cmpSubtaskContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT);
            ((ScrolledComposite) cmpSubtaskContainer.getParent()).setMinSize(childSize);
        }
        cmpSubtaskContainer.getParent().getParent().layout();
        cmpSubtaskContainer.getParent().layout();
    }

    protected Composite createTitleArea(Composite parent) {
        Composite cmpTitle = super.createTitleArea(parent);
        // ( (GridData) cmpTitle.getLayoutData( ) ).heightHint = 250;

        previewCanvas = new Canvas(cmpTitle, SWT.BORDER);
        {
            GridData gd = new GridData(GridData.FILL_BOTH);
            gd.horizontalSpan = 2;
            previewCanvas.setLayoutData(gd);
            previewCanvas.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
        }
        return cmpTitle;
    }

    protected String getTitleAreaString() {
        return Messages.getString("TaskFormatChart.Label.Preview"); //$NON-NLS-1$
    }

    protected void createSubtaskArea(Composite parent, ISubtaskSheet subtask) {
        if (getNavigatorTree().getSelection().length > 0) {
            lblNodeTitle.setText(getNavigatorTree().getSelection()[0].getText());
        }
        super.createSubtaskArea(parent, subtask);

        // If the subtask is registered as disabled state, disable it.
        boolean bEnabled = ((ChartWizardContext) getContext()).isEnabled(subtask.getNodePath());
        if (!bEnabled) {
            disableControl(parent);
        }
        parent.setEnabled(bEnabled);
        lblNodeTitle.setEnabled(bEnabled);
    }

    private void disableControl(Control control) {
        if (control instanceof Composite) {
            Control[] children = ((Composite) control).getChildren();
            for (int i = 0; i < children.length; i++) {
                disableControl(children[i]);
            }
        }
        control.setEnabled(false);
    }

    public IChartPreviewPainter createPreviewPainter() {
        ChartPreviewPainter painter = new ChartPreviewPainter((ChartWizardContext) getContext());
        getPreviewCanvas().addPaintListener(painter);
        getPreviewCanvas().addControlListener(painter);
        painter.setPreview(getPreviewCanvas());
        return painter;
    }

    public void changeTask(Notification notification) {
        if (isSutaskPreviewable(getCurrentSubtask())) {
            if (getCurrentSubtask() instanceof ITaskChangeListener) {
                // Delegate notification to previewable subtask
                ((ITaskChangeListener) getCurrentSubtask()).changeTask(notification);
            }
        } else {
            if (previewPainter != null) {
                doPreview();
            }
        }
    }

    protected IDataServiceProvider getDataServiceProvider() {
        return ((ChartWizardContext) getContext()).getDataServiceProvider();
    }

    protected void initialize(Chart chartModel) {
        // Register sheet collections
        registerSheetCollection(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITH_AXES);
        registerSheetCollection(BASE_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
        registerSheetCollection(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
        registerSheetCollection(BASE_AXIS_SHEET_COLLECTION);
        registerSheetCollection(ORTHOGONAL_AXIS_SHEET_COLLECTION);
        registerSheetCollection(ANCILLARY_AXIS_SHEET_COLLECTION);
        registerSheetCollection(DIAL_SERIES_SHEET_COLLECTION);

        if (chartModel instanceof ChartWithAxes) {
            iBaseAxisCount = ((ChartWithAxes) chartModel).getAxes().size();
            iOrthogonalAxisCount = 0;
            iAncillaryAxisCount = 0;
            iOrthogonalSeriesCount = 0;
            for (int i = 0; i < iBaseAxisCount; i++) {
                iOrthogonalAxisCount += ((ChartWithAxes) chartModel).getAxes().get(i).getAssociatedAxes().size();
                if (chartModel.getDimension().getValue() == ChartDimension.THREE_DIMENSIONAL) {
                    iAncillaryAxisCount += ((ChartWithAxes) chartModel).getAxes().get(i).getAncillaryAxes().size();
                }
                if (isMultipleValueSeriesAllowed()) {
                    for (int iS = 0; iS < iOrthogonalAxisCount; iS++) {
                        iOrthogonalSeriesCount += ((ChartWithAxes) chartModel).getAxes().get(i).getAssociatedAxes()
                                .get(iS).getSeriesDefinitions().size();
                    }
                } else {
                    iOrthogonalSeriesCount = 1;
                }
            }
            // Start from 1 because there will always be at least 1 entry for
            // each registered sheet when this method is called
            for (int iBA = 1; iBA < iBaseAxisCount; iBA++) {
                addCollectionInstance(BASE_AXIS_SHEET_COLLECTION);
            }

            for (int iOA = 1; iOA < iOrthogonalAxisCount; iOA++) {
                addCollectionInstance(ORTHOGONAL_AXIS_SHEET_COLLECTION);
            }

            // Remove Z axis by default
            removeCollectionInstance(ANCILLARY_AXIS_SHEET_COLLECTION);
            // Must start from 0 because default is 0
            for (int iOA = 0; iOA < iAncillaryAxisCount; iOA++) {
                addCollectionInstance(ANCILLARY_AXIS_SHEET_COLLECTION);
            }
            // Remove series sheets (for charts with axes) since they are not
            // needed for Charts Without Axes
            removeCollectionInstance(BASE_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
            removeCollectionInstance(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
            removeCollectionInstance(DIAL_SERIES_SHEET_COLLECTION);

            for (int iOS = 1; iOS < iOrthogonalSeriesCount; iOS++) {
                addCollectionInstance(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITH_AXES);
            }
        } else {
            iBaseAxisCount = 0;
            iOrthogonalAxisCount = 0;
            iBaseSeriesCount = ((ChartWithoutAxes) chartModel).getSeriesDefinitions().size();

            if (isMultipleValueSeriesAllowed()) {
                iOrthogonalSeriesCount = 0;
                for (int iS = 0; iS < iBaseSeriesCount; iS++) {
                    iOrthogonalSeriesCount += ((ChartWithoutAxes) chartModel).getSeriesDefinitions().get(iS)
                            .getSeriesDefinitions().size();
                }
            } else {
                iOrthogonalSeriesCount = 1;
            }

            // Remove axis sheets since they are not needed for Charts Without
            // Axes
            removeCollectionInstance(ANCILLARY_AXIS_SHEET_COLLECTION);
            removeCollectionInstance(ORTHOGONAL_AXIS_SHEET_COLLECTION);
            removeCollectionInstance(BASE_AXIS_SHEET_COLLECTION);
            // Remove series sheets (for charts with axes) since they are not
            // needed for Charts Without Axes
            removeCollectionInstance(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITH_AXES);
            removeCollectionInstance(BASE_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
            removeCollectionInstance(DIAL_SERIES_SHEET_COLLECTION);

            if (chartModel instanceof DialChart) {
                if (!((DialChart) chartModel).isDialSuperimposition()) {
                    for (int iOS = 1; iOS < iOrthogonalSeriesCount; iOS++) {
                        addCollectionInstance(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
                    }
                } else {
                    for (int iOS = 0; iOS < iOrthogonalSeriesCount; iOS++) {
                        addCollectionInstance(DIAL_SERIES_SHEET_COLLECTION);
                    }
                }
            } else {
                // Only add category series page for Pie chart, since default
                // behavior is no category series settings.
                if (((ChartWizardContext) getContext()).getChartType() instanceof PieChart) {
                    for (int iBS = 0; iBS < iBaseSeriesCount; iBS++) {
                        addCollectionInstance(BASE_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
                    }
                }
                for (int iOS = 1; iOS < iOrthogonalSeriesCount; iOS++) {
                    addCollectionInstance(ORTHOGONAL_SERIES_SHEET_COLLECTION_FOR_CHARTS_WITHOUT_AXES);
                }
            }
        }
    }

    public void dispose() {
        super.dispose();

        if (htVisibleSheets != null) {
            htVisibleSheets.clear();
        }
        if (htSheetCollections != null) {
            htSheetCollections.clear();
        }

        previewCanvas = null;
        if (previewPainter != null) {
            previewPainter.dispose();
        }
        previewPainter = null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.birt.core.ui.frameworks.taskwizard.SimpleTask#getImage()
     */
    public Image getImage() {
        return UIHelper.getImage(ChartUIConstants.IMAGE_TASK_FORMAT);
    }

    protected boolean isSutaskPreviewable(ISubtaskSheet subtask) {
        return subtask instanceof ITaskPreviewable && ((ITaskPreviewable) subtask).isPreviewable();
    }

    protected Chart getPreviewChartModel() throws ChartException {
        return getCurrentModelState();
    }

    public void doPreview() {
        try {
            final Chart chart = getPreviewChartModel();
            LivePreviewTask lpt = new LivePreviewTask(
                    Messages.getString("TaskFormatChart.LivePreviewTask.BindData"), null); //$NON-NLS-1$
            // Add a task to retrieve data and bind data to chart.
            lpt.addTask(new LivePreviewTask() {
                public void run() {
                    if (previewPainter != null) {
                        setParameter(ChartLivePreviewThread.PARAM_CHART_MODEL, ChartUIUtil.prepareLivePreview(chart,
                                getDataServiceProvider(), ((ChartWizardContext) context).getActionEvaluator()));
                    }
                }
            });

            // Add a task to render chart.
            lpt.addTask(new LivePreviewTask() {
                public void run() {
                    if (previewCanvas != null && previewCanvas.getDisplay() != null
                            && !previewCanvas.getDisplay().isDisposed()) {
                        previewCanvas.getDisplay().syncExec(new Runnable() {

                            public void run() {
                                // Repaint chart.
                                if (previewPainter != null) {
                                    previewPainter.renderModel(
                                            (IChartObject) getParameter(ChartLivePreviewThread.PARAM_CHART_MODEL));
                                }
                            }
                        });
                    }
                }
            });

            // Add live preview tasks to live preview thread.
            ((ChartLivePreviewThread) ((ChartWizardContext) context).getLivePreviewThread())
                    .setParentShell(getPreviewCanvas().getShell());
            ((ChartLivePreviewThread) ((ChartWizardContext) context).getLivePreviewThread()).add(lpt);
        } catch (ChartException e) {
            WizardBase.showException(e.getMessage());
        }
    }

    public Canvas getPreviewCanvas() {
        return previewCanvas;
    }

    public boolean isPreviewable() {
        return true;
    }

}