org.dawnsci.breadcrumb.navigation.views.AbstractNavigationView.java Source code

Java tutorial

Introduction

Here is the source code for org.dawnsci.breadcrumb.navigation.views.AbstractNavigationView.java

Source

/*
 * Copyright (c) 2012 Diamond Light Source Ltd.
 *
 * 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
 */
package org.dawnsci.breadcrumb.navigation.views;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

import org.dawb.common.ui.menu.CheckableActionGroup;
import org.dawb.common.ui.preferences.ViewConstants;
import org.dawb.common.ui.util.GridUtils;
import org.dawb.common.ui.viewers.TreeNodeContentProvider;
import org.dawb.common.ui.views.CompositeSelectionProvider;
import org.dawnsci.breadcrumb.navigation.Activator;
import org.dawnsci.breadcrumb.navigation.preference.NavigationConstants;
import org.dawnsci.breadcrumb.navigation.table.AbstractLazyLabelProvider;
import org.dawnsci.breadcrumb.navigation.table.ISortParticipant;
import org.dawnsci.common.widgets.action.SpacerContributionItem;
import org.dawnsci.common.widgets.breadcrumb.BreadcrumbViewer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.part.ViewPart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The main breadcrumb view allowing people to 
 * click their way down to the data collection required.
 * 
 * This view is the entry to navigating the visit. 
 * 
 * @author Matthew Gerring
 *
 */
public abstract class AbstractNavigationView extends ViewPart
        implements ISelectionChangedListener, ISortParticipant {

    protected static final Logger logger = LoggerFactory.getLogger(AbstractNavigationView.class);

    // UI
    protected Map<INavigationDelegateMode, INavigationDelegate> pages;

    private List<StyledTreeBreadcrumbViewer> bviewers;
    private Composite crumbs;

    private StackLayout contextStack;
    private Composite card;

    private INavigationDelegateMode navigationMode;

    // Services
    protected IDataSourceManager connectionManager;

    public AbstractNavigationView() {
        this.bviewers = new ArrayList<StyledTreeBreadcrumbViewer>(3);
        this.connectionManager = createConnectionManager();
        this.pages = createPages();
        this.navigationMode = getDefaultNavigationMode();
    }

    /**
     * The mode which should be the table delegate by default
     * @return
     */
    protected abstract INavigationDelegateMode getDefaultNavigationMode();

    /**
     * The various table delegate pages which will be the content of the view.
     * @return
     */
    protected abstract Map<INavigationDelegateMode, INavigationDelegate> createPages();

    /**
     * The connection manager which mananges connection to the data source.
     * @return
     */
    protected abstract IDataSourceManager createConnectionManager();

    /**
     * 
     * @return the label provider for the breadcrumbs
     */
    protected abstract IStyledTreeLabelProvider createBreadcrumbLabelProvider();

    /**
     * Please implement to return your implementation of the StyledTreeBreadcrumbViewer
     * @param container
     * @param horizontal
     * @return
     */
    protected abstract StyledTreeBreadcrumbViewer createBreadcrumbViewer(Composite container, int horizontal);

    /**
     * The preference page for the connection or null if there is not one.
     * @return
     */
    protected abstract String getPreferencePageId();

    @Override
    public void createPartControl(Composite ancestor) {
        createUI(ancestor);
        createActions();
        connectionManager.connect();

        setActiveUI(pages.get(navigationMode).getControl(), null);
    }

    private void createUI(Composite ancestor) {

        final Composite parent = new Composite(ancestor, SWT.NONE);
        parent.setLayout(new GridLayout(1, false));
        GridUtils.removeMargins(parent);

        // A Breadcrumb similar to eclipses one, which is cool.
        this.crumbs = new Composite(parent, SWT.NONE);
        crumbs.setLayout(new GridLayout(1, false));
        crumbs.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        GridUtils.removeMargins(crumbs);

        // Adds the primary viewer to the view. Others may be added to compare but these
        // can be removed again. This primary one cannot.
        StyledTreeBreadcrumbViewer bviewer = createBreadcrumbViewer(crumbs, false);
        bviewers.add(bviewer);

        this.card = new Composite(parent, SWT.NONE);
        this.contextStack = new StackLayout();
        card.setLayout(contextStack);
        card.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        // Create all the tables on the card.
        for (INavigationDelegateMode mode : pages.keySet()) {
            final INavigationDelegate vtp = pages.get(mode);
            vtp.createContent("", mode.getTooltip(), card);
        }

        // We create a compound selection provider that can 
        // amalgamate the two sources of selection.
        final CompositeSelectionProvider prov = new CompositeSelectionProvider();
        for (INavigationDelegateMode mode : navigationMode.allValues()) {
            if (pages.containsKey(mode)) {
                prov.addProvider(pages.get(mode).getSelectionProvider());
            }
        }
        getViewSite().setSelectionProvider(prov);

    }

    private StyledTreeBreadcrumbViewer createBreadcrumbViewer(final Composite crumbs, boolean isSecondaryViewer) {

        final StyledTreeBreadcrumbViewer bviewer;
        if (isSecondaryViewer) {
            final Composite container = new Composite(crumbs, SWT.NONE);
            container.setLayout(new GridLayout(2, false));
            container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

            GridUtils.removeMargins(container);
            bviewer = createBreadcrumbViewer(container, SWT.HORIZONTAL);
            bviewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

            final ToolBar toolbar = new ToolBar(container, SWT.FLAT);
            toolbar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));

            final ToolItem remove = new ToolItem(toolbar, SWT.PUSH);
            remove.setImage(Activator.getImageDescriptor("icons/ui-tooltip--minus.png").createImage());
            remove.setToolTipText("Remove this breadcrumb from the combined searach.");

            crumbs.layout(new Control[] { container });
            crumbs.getParent().layout();

            remove.addSelectionListener(new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    removeSelectedBreadcrumb(container, bviewer);
                }
            });
        } else {
            bviewer = createBreadcrumbViewer(crumbs, SWT.HORIZONTAL);
            bviewer.setPrimaryViewer(true);
        }

        ITreeContentProvider prov = new TreeNodeContentProvider();
        bviewer.setLabelProvider(createBreadcrumbLabelProvider());
        bviewer.setToolTipLabelProvider(new ColumnLabelProvider());
        bviewer.setContentProvider(prov);

        bviewer.addSelectionChangedListener(this);

        return bviewer;
    }

    /**
     * You may override this to do more work when a breadcrub is removed.
     * @param container
     * @param bviewer
     */
    protected void removeSelectedBreadcrumb(final Composite container, StyledTreeBreadcrumbViewer bviewer) {
        bviewers.remove(bviewer);
        GridUtils.setVisible(container, false);
        crumbs.layout(new Control[] { container });
        crumbs.getParent().layout();
        container.dispose();

        selectionChanged(null);
    }

    protected int getBreadcrumbCount() {
        return bviewers.size();
    }

    @Override
    public void saveSearch(final String searchString) {
        AbstractTableDelegate dele = (AbstractTableDelegate) pages.get(navigationMode);
        dele.saveSearch(searchString);
    }

    @Override
    public void setEnabled(final boolean enabled) {
        Display.getDefault().syncExec(new Runnable() {
            public void run() {
                final ToolBarManager man = (ToolBarManager) getViewSite().getActionBars().getToolBarManager();
                if (man == null || man.getControl() == null)
                    return;
                man.getControl().setEnabled(enabled);

                for (BreadcrumbViewer bviewer : bviewers)
                    bviewer.getControl().setEnabled(enabled);

                for (INavigationDelegateMode mode : pages.keySet()) {
                    pages.get(mode).setEnabled(enabled);
                }
            }
        });
    }

    public void init(IViewSite site, IMemento memento) throws PartInitException {
        init(site);
        connectionManager.init(memento);
    }

    protected void createActions() {

        final IToolBarManager man = getViewSite().getActionBars().getToolBarManager();
        final MenuManager menuMan = new MenuManager();

        man.add(new Separator("breadcrumb.group"));

        Action add = new Action("Add another breadcrumb search",
                Activator.getImageDescriptor("icons/ui-tooltip--plus.png")) {
            public void run() {
                addBreadcrumb();
            }
        };
        man.add(add);

        man.add(new Separator("refresh.group"));
        menuMan.add(new Separator("refresh.group"));

        Action refresh = new Action("Refresh table", Activator.getImageDescriptor("icons/refresh_16x16.png")) {
            public void run() {
                refreshDataCollections();
            }
        };
        man.add(refresh);

        refresh = new Action("Refresh connection", Activator.getImageDescriptor("icons/refresh_red.png")) {
            public void run() {
                boolean ok = MessageDialog.openConfirm(Display.getDefault().getActiveShell(),
                        "Confirm Full Refresh",
                        "Are you sure that you would like to do a complete refresh?\n\nThis will loose your selected visit(s) and ask you to start again.");
                if (!ok)
                    return;
                connectionManager.logoff();
                connectionManager.connect();
            }
        };
        man.add(refresh);

        // Actions to search data collection table
        for (INavigationDelegateMode mode : pages.keySet()) {
            INavigationDelegate delegate = pages.get(mode);
            if (delegate instanceof AbstractTableDelegate) {
                ((AbstractTableDelegate) delegate).createActions(getViewSite().getActionBars().getToolBarManager(),
                        menuMan);
            }
        }

        // Actions to log in and log out
        connectionManager.createLogActions(getViewSite().getActionBars().getToolBarManager());

        man.add(new Separator("preference.group"));
        menuMan.add(new Separator("preference.group"));

        if (getPreferencePageId() != null) {
            Action ispyPref = new Action("Preferences... (Connection and polling)",
                    Activator.getImageDescriptor("icons/data.gif")) {
                @Override
                public void run() {
                    PreferenceDialog pref = PreferencesUtil.createPreferenceDialogOn(
                            PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), getPreferencePageId(),
                            null, null);
                    if (pref != null)
                        pref.open();
                }
            };
            man.add(ispyPref);
            getViewSite().getActionBars().getMenuManager().add(ispyPref);
        }

        Action prefs = new Action("Image Preferences... (For data collection images in gallery)",
                Activator.getImageDescriptor("icons/data.gif")) {
            @Override
            public void run() {
                PreferenceDialog pref = PreferencesUtil.createPreferenceDialogOn(
                        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), ViewConstants.PAGE_ID,
                        null, null);
                if (pref != null)
                    pref.open();
            }
        };

        getViewSite().getActionBars().getMenuManager().add(prefs);
        menuMan.add(prefs);

        man.add(new SpacerContributionItem(50));

        final CheckableActionGroup grp = new CheckableActionGroup();
        for (final INavigationDelegateMode mode : getDefaultNavigationMode().allValues()) {
            if (mode.isInToolbar()) {
                final Action action = new Action(mode.getLabel(), IAction.AS_CHECK_BOX) {
                    public void run() {
                        navigationMode = mode;
                        final INavigationDelegate prov = pages.get(mode);
                        if (prov != null) {
                            setActiveUI(prov.getControl(), mode);
                            selectionChanged(null);
                            // TODO Might want to leave selection so that do not loose plots one day.
                            prov.getSelectionProvider().setSelection(prov.getSelectionProvider().getSelection());
                        }
                    }
                };
                action.setId(mode.getId());
                action.setImageDescriptor(mode.getIcon());

                final ActionContributionItem item = new ActionContributionItem(action);
                if (Activator.getDefault().getPreferenceStore().getBoolean(NavigationConstants.SHOW_MODE_LABEL)) {
                    item.setMode(ActionContributionItem.MODE_FORCE_TEXT);
                }
                man.add(item);
                grp.add(action);
                action.setChecked(navigationMode == mode);
            }
        }
        man.add(new Separator("tablemode.group"));
        menuMan.add(new Separator("tablemode.group"));

        Activator.getDefault().getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent event) {
                if (NavigationConstants.SHOW_MODE_LABEL.equals(event.getProperty())) {
                    boolean isShowLabel = Activator.getDefault().getPreferenceStore()
                            .getBoolean(NavigationConstants.SHOW_MODE_LABEL);
                    int modeCode = isShowLabel ? ActionContributionItem.MODE_FORCE_TEXT : 0;
                    for (final INavigationDelegateMode mode : getDefaultNavigationMode().allValues()) {
                        final IContributionItem item = man.find(mode.getId());
                        if (item instanceof ActionContributionItem) {
                            ((ActionContributionItem) item).setMode(modeCode);
                        }
                    }
                    man.update(true);
                }
            }
        });

        for (INavigationDelegateMode mode : pages.keySet()) {
            INavigationDelegate delegate = pages.get(mode);
            if (delegate instanceof AbstractTableDelegate) {
                ((AbstractTableDelegate) delegate).setMenu(menuMan);
            }
        }

    }

    protected boolean addBreadcrumb() {
        if (!connectionManager.isConnected()) {
            MessageDialog.openWarning(Display.getDefault().getActiveShell(), "There is no collection to the data",
                    "DAWN cannot connect to the data at the moment.\n\nPlease press the reconnect button.");
            return false;
        }
        final StyledTreeBreadcrumbViewer bviewer = createBreadcrumbViewer(crumbs, true);
        bviewer.setInput(connectionManager.createContent());
        bviewers.add(bviewer);

        return true;
    }

    protected void refreshDataCollections() {
        refreshTable();
        selectionChanged((SelectionChangedEvent) null);
    }

    public void refreshTable() {
        INavigationDelegate prov = pages.get(navigationMode);
        prov.refresh();
    }

    @Override
    public void setFocus() {
        bviewers.get(0).setFocus();
    }

    @Override
    public void dispose() {
        for (INavigationDelegate prov : pages.values())
            prov.dispose();
        for (BreadcrumbViewer bviewer : bviewers)
            bviewer.removeSelectionChangedListener(this);
        bviewers.clear();
        super.dispose();
    }

    /**
     * event may be null to read selections from nodes.
     */
    @Override
    public void selectionChanged(SelectionChangedEvent event) {

        List<TreeNode> nodes = getNodes(event);

        try {
            if (nodes == null || nodes.isEmpty() || ((DefaultMutableTreeNode) nodes.get(0)).getUserObject() == null)
                return;

            Object uObject = ((DefaultMutableTreeNode) nodes.get(0)).getUserObject();
            INavigationDelegateMode specificMode = getSpecificNavigationMode(uObject);
            INavigationDelegateMode mode = specificMode != null ? specificMode
                    : findSelectedMode(getDefaultNavigationMode());
            updateSelectedNodes(nodes, mode);

        } catch (Throwable ne) {
            logger.error("Unabled to select nodes!", ne);
        }
    }

    /**
     * Implement to provide modes for specific user objects. For instance if a selection
     * of this type, use a specific INavigationDelegate for this object.
     * 
     * @param uObject
     * @return
     */
    protected INavigationDelegateMode getSpecificNavigationMode(Object uObject) {
        return null;
    }

    private INavigationDelegateMode findSelectedMode(INavigationDelegateMode defaultMode) {
        final IContributionManager man = getViewSite().getActionBars().getToolBarManager();
        for (final INavigationDelegateMode mode : defaultMode.allValues()) {
            final IContributionItem item = man.find(mode.getId());
            if (item != null && item instanceof ActionContributionItem) {
                if (((ActionContributionItem) item).getAction().isChecked())
                    return mode;
            }
        }
        return defaultMode;
    }

    private List<TreeNode> getNodes(SelectionChangedEvent event) {

        final Object sel = event != null ? ((StructuredSelection) event.getSelection()).getFirstElement() : null;

        final List<TreeNode> nodes;
        if (sel != null && getSpecificNavigationMode(((DefaultMutableTreeNode) sel).getUserObject()) != null) {
            nodes = new ArrayList<TreeNode>();
            nodes.add((TreeNode) sel);
        } else {
            // Add them all
            nodes = getSelectedVisits();
        }
        return nodes;
    }

    /**
     * The visits selected in the current viewers, thread safe
     * @return
     */
    public List<TreeNode> getSelectedVisits() {

        if (Thread.currentThread() == Display.getDefault().getThread()) {
            return getSelectedVisitsInternal();
        } else {
            final List<TreeNode> nodes = new ArrayList<TreeNode>();
            Display.getDefault().syncExec(new Runnable() {
                public void run() {
                    List<TreeNode> ns = getSelectedVisitsInternal();
                    if (ns != null)
                        nodes.addAll(ns);
                }
            });
            return nodes;
        }
    }

    private List<TreeNode> getSelectedVisitsInternal() {
        final List<TreeNode> nodes = new ArrayList<TreeNode>();
        for (BreadcrumbViewer bViewer : bviewers) {
            StructuredSelection ss = (StructuredSelection) bViewer.getSelection();
            final Object s = ss.getFirstElement();
            if (s == null)
                continue;
            if (!(s instanceof TreeNode))
                continue;
            nodes.add((TreeNode) s);
        }
        return nodes;
    }

    public INavigationDelegateMode getNavigationMode() {
        return navigationMode;
    }

    public void updateSelectedNodes(List<TreeNode> nodes, INavigationDelegateMode mode) {

        List<Object> selections = new ArrayList<Object>();
        for (TreeNode sel : nodes) {
            final Object uObject = ((DefaultMutableTreeNode) sel).getUserObject();
            if (uObject == null)
                continue;
            selections.add(uObject);
        }

        // Need a job for these, can be large
        AbstractTableDelegate dele = (AbstractTableDelegate) pages.get(mode);
        dele.schedule(selections, connectionManager.getBean());

        navigationMode = mode;

    }

    public void saveState(IMemento memento) {
        connectionManager.saveState(memento);
    }

    /**
     * 
     * @param control
     * @param mode -  may be null. If null, toolbar will not be updated.
     */
    public void setActiveUI(Control control, INavigationDelegateMode mode) {

        contextStack.topControl = control;
        card.layout();

        if (mode != null) {
            IContributionManager man = getViewSite().getActionBars().getToolBarManager();
            for (INavigationDelegateMode key : pages.keySet())
                pages.get(key).setActionsActive(false, man);
            pages.get(mode).setActionsActive(true, man);
            setPartName(mode.getLabel());
            if (mode.hasIcon()) {
                AbstractNavigationView.this.setTitleImage(mode.getIcon().createImage());
            }
            man.update(true);
        }
    }

    public List<StyledTreeBreadcrumbViewer> getViewers() {
        return new ArrayList<StyledTreeBreadcrumbViewer>(bviewers);
    }

    /**
     * Thread safe
     * @param cursorWait
     */
    public void setCursor(final int cursorCode) {
        Display.getDefault().syncExec(new Runnable() {
            public void run() {

                final Cursor cursor = cursorCode > 0 ? Display.getDefault().getSystemCursor(cursorCode) : null;
                for (BreadcrumbViewer bvewier : bviewers)
                    bvewier.getControl().setCursor(cursor);
                for (INavigationDelegate prov : pages.values())
                    prov.setCursor(cursor);
            }
        });
    }

    @Override
    public AbstractLazyLabelProvider getLabelProvider() {
        AbstractTableDelegate dele = (AbstractTableDelegate) pages.get(navigationMode);
        return dele.labelProvider;
    }

    protected void setNavigationMode(INavigationDelegateMode mode) {
        this.navigationMode = mode;
    }

    @Override
    public Object getAdapter(Class adapter) {

        if (navigationMode != null) {
            INavigationDelegate dele = pages.get(this.navigationMode);
            if (dele != null) {
                Object ret = dele.getAdapter(adapter);
                if (ret != null)
                    return ret;
            }
        }
        return super.getAdapter(adapter);
    }

}