rabbit.ui.internal.RabbitView.java Source code

Java tutorial

Introduction

Here is the source code for rabbit.ui.internal.RabbitView.java

Source

/*
 * Copyright 2010 The Rabbit Eclipse Plug-in Project
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package rabbit.ui.internal;

import rabbit.tracking.internal.TrackingPlugin;
import rabbit.ui.IPage;
import rabbit.ui.Preference;

import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
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.DateTime;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A view to show metrics.
 */
public class RabbitView extends ViewPart {

    /** Preference constant for saving/restoring the view state. */
    private static final String PREF_RABBIT_VIEW = "rabbitView";

    /** Preference constant for saving/restoring the view state. */
    private static final String PREF_METRICS_WIDTH = "metricsPanelWidth";

    /**
     * Checks whether the two calendars has the same year, month, and day of
     * month.
     * 
     * @param date1 The calendar.
     * @param date2 The other calendar.
     * @return True if the dates has the same year, month, and day of month, false
     *         otherwise.
     */
    public static boolean isSameDate(Calendar date1, Calendar date2) {
        return date1.get(Calendar.YEAR) == date2.get(Calendar.YEAR)
                && date1.get(Calendar.MONTH) == date2.get(Calendar.MONTH)
                && date1.get(Calendar.DAY_OF_MONTH) == date2.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * Updates the date with the data from the widget.
     * 
     * @param date The date to be updated.
     * @param widget The widget to get the data from.
     */
    public static void updateDate(Calendar date, DateTime widget) {
        date.set(Calendar.YEAR, widget.getYear());
        date.set(Calendar.MONTH, widget.getMonth());
        date.set(Calendar.DAY_OF_MONTH, widget.getDay());
    }

    /**
     * Updates the widget with the data from the date.
     * 
     * @param widget The widget to be updated.
     * @param date The date to get the data from.
     */
    public static void updateDateTime(DateTime widget, Calendar date) {
        widget.setYear(date.get(Calendar.YEAR));
        widget.setMonth(date.get(Calendar.MONTH));
        widget.setDay(date.get(Calendar.DAY_OF_MONTH));
    }

    /**
     * Gets the version of Eclipse. Not completely reliable.
     * 
     * @return The version String, such as 3.5..., or an empty String.
     */
    private static String getProductVersion() {
        try {
            IProduct product = Platform.getProduct();
            String aboutText = product.getProperty("aboutText");
            String pattern = "Version: (.*)\n";
            Pattern p = Pattern.compile(pattern);
            Matcher m = p.matcher(aboutText);
            return (m.find()) ? m.group(1) : "";
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * A map containing page status (updated or not), if a page is not updated
     * (value return false), then it will be updated before it's displayed (when a
     * user clicks on a tree node).
     */
    private Map<IPage, Boolean> pageStatus;

    /** A map containing pages and the root composite of the page. */
    private Map<IPage, Composite> pages;

    /** A map containing pages and their tool bar items. */
    private Map<IPage, IContributionItem[]> pageToolItems;

    /** A tool bar for pages to create their tool bar items. */
    private IToolBarManager extensionToolBar;

    private FormToolkit toolkit;

    /**
     * The layout of {@link #displayPanel}, used to show/hide pages on user 
     * selection.
     */
    private StackLayout stackLayout;

    /** The composite to show the page that is selected by the user. */
    private Composite displayPanel;

    /** The preferences for the pages. */
    private final Preference preferences;

    /** True if this OS is Windows, false otherwise. */
    private final boolean isWindowsOS = Platform.getOS().equals(Platform.OS_WIN32);

    /** True if this OS is linux, false otherwise. */
    private final boolean isLinux = Platform.getOS().equals(Platform.OS_LINUX);

    /** File to save/restore the view state, may be null. */
    private IMemento memento;

    /** The form data of the sash dividing the two panels. */
    private FormData sashFormData;

    /**
     * Constructs a new view.
     */
    public RabbitView() {
        pages = new HashMap<IPage, Composite>();
        pageStatus = new HashMap<IPage, Boolean>();
        pageToolItems = new HashMap<IPage, IContributionItem[]>();

        toolkit = new FormToolkit(PlatformUI.getWorkbench().getDisplay());
        stackLayout = new StackLayout();
        preferences = new Preference();
    }

    @Override
    public void createPartControl(Composite parent) {
        Form form = toolkit.createForm(parent);
        form.getBody().setLayout(new FormLayout());

        sashFormData = new FormData();
        sashFormData.width = 1;
        sashFormData.top = new FormAttachment(0, 0);
        sashFormData.left = new FormAttachment(0, 200);
        sashFormData.bottom = new FormAttachment(100, 0);
        final Sash sash = new Sash(form.getBody(), SWT.VERTICAL);
        sash.setBackground(toolkit.getColors().getBorderColor());
        sash.setLayoutData(sashFormData);
        sash.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event e) {
                ((FormData) sash.getLayoutData()).left = new FormAttachment(0, e.x);
                sash.getParent().layout();
            }
        });

        // Extension list:
        FormData leftData = new FormData();
        leftData.top = new FormAttachment(0, 0);
        leftData.left = new FormAttachment(0, 0);
        leftData.right = new FormAttachment(sash, 0);
        leftData.bottom = new FormAttachment(100, 0);
        Form left = toolkit.createForm(form.getBody());
        left.setText("Metrics");
        left.setLayoutData(leftData);
        left.getBody().setLayout(new FillLayout());
        MetricsPanel list = new MetricsPanel(this);
        list.createContents(left.getBody());

        // Displaying area:
        FormData rightData = new FormData();
        rightData.top = new FormAttachment(0, 0);
        rightData.left = new FormAttachment(sash, 0);
        rightData.right = new FormAttachment(100, 0);
        rightData.bottom = new FormAttachment(100, 0);

        Composite right = toolkit.createComposite(form.getBody());
        right.setLayoutData(rightData);
        GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(right);

        // Header:
        Composite header = toolkit.createComposite(right);
        GridLayout headerLayout = new GridLayout(2, false);
        if (isLinux) { // Make GTK widgets have less spaces:
            headerLayout.marginHeight = 0;
            headerLayout.marginWidth = 0;
            headerLayout.horizontalSpacing = 0;
            headerLayout.verticalSpacing = 0;
        }
        header.setLayout(headerLayout);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(header);
        {
            int toolbarStyle = (!isLinux) ? SWT.FLAT : SWT.NONE;

            ToolBar bar = new ToolBar(header, toolbarStyle);
            bar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
            toolkit.adapt(bar, false, false);
            extensionToolBar = new ToolBarManager(bar);

            bar = new ToolBar(header, toolbarStyle);
            toolkit.adapt(bar, false, false);
            createToolBarItems(new ToolBarManager(bar));
        }
        displayPanel = toolkit.createComposite(right);
        displayPanel.setLayout(stackLayout);
        GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(displayPanel);

        // Greeting message:
        Composite cmp = toolkit.createComposite(displayPanel);
        cmp.setLayout(new GridLayout());
        {
            Label imgLabel = toolkit.createLabel(cmp, "", SWT.CENTER);
            imgLabel.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, true));
            imgLabel.setImage(getTitleImage());

            Label helloLabel = toolkit.createLabel(cmp, "Welcome!", SWT.CENTER);
            helloLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true));
        }
        stackLayout.topControl = cmp;
        displayPanel.layout();

        if (memento != null) {
            restoreState(memento);
        }
    }

    /**
     * Displays the given page.
     * 
     * @param page The page to display.
     */
    public void display(IPage page) {
        // Removes the extension tool bar items:
        for (IContributionItem item : extensionToolBar.getItems()) {
            item.setVisible(false);
        }

        Composite cmp = null;
        if (page != null) {

            // Updates the page:
            cmp = pages.get(page);
            if (cmp == null) {
                cmp = toolkit.createComposite(displayPanel);
                cmp.setLayout(new FillLayout());
                page.createContents(cmp);
                pages.put(page, cmp);

                // Restores the state:
                if (memento != null) {
                    page.onRestoreState(memento);
                }
            }

            // Updates the extension tool bar items:
            IContributionItem[] items = pageToolItems.get(page);
            if (items == null) {
                items = page.createToolBarItems(extensionToolBar);
                pageToolItems.put(page, items);
            } else {
                for (IContributionItem item : items) {
                    item.setVisible(true);
                }
            }

            // Updates the current visible page, mark others as not updated:
            Boolean updated = pageStatus.get(page);
            if (updated == null || !updated) {
                pageStatus.put(page, Boolean.TRUE);
                updatePage(page, preferences);
            }
        }

        extensionToolBar.update(true);
        stackLayout.topControl = cmp;
        displayPanel.layout();
    }

    @Override
    public void dispose() {
        toolkit.dispose();
        super.dispose();
    }

    @Override
    public void init(IViewSite site, IMemento m) throws PartInitException {
        super.init(site, m);
        if (m != null) {
            this.memento = m.getChild(PREF_RABBIT_VIEW);
        }
    }

    @Override
    public void saveState(IMemento memento) {
        memento = memento.createChild(PREF_RABBIT_VIEW);
        memento.putInteger(PREF_METRICS_WIDTH, sashFormData.left.offset);
        for (IPage page : pages.keySet()) {
            page.onSaveState(memento);
        }
    }

    @Override
    public void setFocus() {
    }

    private void createSpace(IToolBarManager toolBar) {
        createString(toolBar, "  ");
    }

    private void createString(IToolBarManager toolBar, final String str) {
        toolBar.add(new ControlContribution(null) {
            @Override
            protected Control createControl(Composite parent) {
                return toolkit.createLabel(parent, str);
            }
        });
    }

    /**
     * Creates tool bar items for non windows operating systems.
     * 
     * @param toolBar The tool bar.
     */
    private void createToolBarForNonWindowsOS(IToolBarManager toolBar) {
        CalendarAction.create(toolBar, getSite().getShell(), preferences.getStartDate(), " From: ", " ");
        CalendarAction.create(toolBar, getSite().getShell(), preferences.getEndDate(), " To: ", " ");
    }

    /**
     * Creates tool bar items for Windows operating system.
     * 
     * @param toolBar The tool bar.
     */
    private void createToolBarForWindowsOS(IToolBarManager toolBar) {
        toolBar.add(new ControlContribution("rabbit.ui.fromDateTime") {
            @Override
            protected Control createControl(Composite parent) {
                final Calendar dateToBind = preferences.getStartDate();
                final DateTime fromDateTime = new DateTime(parent, SWT.DROP_DOWN | SWT.BORDER);
                fromDateTime.setToolTipText("Select the start date for the data to be displayed");
                updateDateTime(fromDateTime, dateToBind);
                fromDateTime.addListener(SWT.Selection, new Listener() {
                    @Override
                    public void handleEvent(Event event) {
                        updateDate(dateToBind, fromDateTime);
                    }
                });
                return fromDateTime;
            }
        });
        createSpace(toolBar);
        toolBar.add(new ControlContribution("rabbit.ui.toDateTime") {
            @Override
            protected Control createControl(Composite parent) {
                final Calendar dateToBind = preferences.getEndDate();
                final DateTime toDateTime = new DateTime(parent, SWT.DROP_DOWN | SWT.BORDER);
                toDateTime.setToolTipText("Select the end date for the data to be displayed");
                updateDateTime(toDateTime, dateToBind);
                toDateTime.addListener(SWT.Selection, new Listener() {
                    @Override
                    public void handleEvent(Event event) {
                        updateDate(dateToBind, toDateTime);
                    }
                });
                return toDateTime;
            }
        });
    }

    /**
     * Creates the tool bar items.
     * 
     * @param toolBar The tool bar.
     */
    private void createToolBarItems(IToolBarManager toolBar) {
        // Only Windows && Eclipse 3.5 has SWT.DROP_DOWN for DateTime.
        // We don't support 3.3 and before anyway:
        boolean isDropDownDateTimeSupported = !getProductVersion().startsWith("3.4");

        if (isWindowsOS && isDropDownDateTimeSupported) {
            createToolBarForWindowsOS(toolBar);
        } else {
            createToolBarForNonWindowsOS(toolBar);
        }

        if (isWindowsOS) { // Looks better:
            createSpace(toolBar);
        }

        IAction refresh = new Action("Refresh") {
            @Override
            public void run() {
                updateView();
            }
        };

        /*
         * Mainly for Eclipse 3.4 (no SWT.DROP_DOWN DateTime) on Windows. Things
         * look ugly on Windows if some tool bar actions have text and some have
         * icons, so in this case, no icons at all.
         */
        if (!isWindowsOS || isDropDownDateTimeSupported) {
            refresh.setImageDescriptor(SharedImages.REFRESH);
        }

        //
        toolBar.add(refresh);
        toolBar.update(true);
    }

    /**
     * Restores the view state.
     * @param memento The settings.
     */
    private void restoreState(IMemento memento) {
        memento = memento.getChild(PREF_RABBIT_VIEW);
        if (memento == null) {
            return;
        }
        Integer width = memento.getInteger(PREF_METRICS_WIDTH);
        if (width != null && width > 0) {
            sashFormData.left.offset = width;
        }
    }

    private void updatePage(final IPage page, final Preference preference) {
        Job job = page.updateJob(preference);
        if (job == null)
            return;

        IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getSite()
                .getService(IWorkbenchSiteProgressService.class);

        service.schedule(job);
    }

    /**
     * Updates the pages to current preference.
     */
    private void updateView() {
        // Sync with today's data:
        Calendar today = Calendar.getInstance();
        if (isSameDate(today, preferences.getEndDate()) || today.before(preferences.getEndDate())) {
            TrackingPlugin.getDefault().saveCurrentData();
        }

        // Mark all invisible pages as "not yet updated":
        for (Map.Entry<IPage, Composite> entry : pages.entrySet()) {
            boolean isVisible = stackLayout.topControl == entry.getValue();
            if (isVisible) {
                // update current visible page.
                updatePage(entry.getKey(), preferences);
            }
            pageStatus.put(entry.getKey(), Boolean.valueOf(isVisible));
        }
    }
}