org.eclipse.egit.ui.internal.history.CommitGraphTable.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.egit.ui.internal.history.CommitGraphTable.java

Source

/*******************************************************************************
 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
 * Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
 *
 * 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.eclipse.egit.ui.internal.history;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.IParameter;
import org.eclipse.core.commands.Parameterization;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.resources.IResource;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIIcons;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.UIText;
import org.eclipse.egit.ui.UIUtils;
import org.eclipse.egit.ui.internal.history.command.HistoryViewCommands;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jgit.revplot.PlotCommit;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.part.IPageSite;

class CommitGraphTable {
    private static Font highlightFont() {
        final Font n, h;

        n = UIUtils.getFont(UIPreferences.THEME_CommitGraphNormalFont);
        h = UIUtils.getFont(UIPreferences.THEME_CommitGraphHighlightFont);

        final FontData[] nData = n.getFontData();
        final FontData[] hData = h.getFontData();
        if (nData.length != hData.length)
            return h;
        for (int i = 0; i < nData.length; i++)
            if (!nData[i].equals(hData[i]))
                return h;

        return UIUtils.getBoldFont(UIPreferences.THEME_CommitGraphNormalFont);
    }

    private static final String LINESEP = System.getProperty("line.separator"); //$NON-NLS-1$

    private final TableViewer table;

    private Clipboard clipboard;

    private final SWTPlotRenderer renderer;

    private final Font nFont;

    private final Font hFont;

    private SWTCommitList allCommits;

    private RevFlag highlight;

    private HistoryPageInput input;

    IAction copy;

    MenuListener menuListener;

    CommitGraphTable(final Composite parent, final IPageSite site, final MenuManager menuMgr) {
        nFont = UIUtils.getFont(UIPreferences.THEME_CommitGraphNormalFont);
        hFont = highlightFont();

        Table rawTable = new Table(parent,
                SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.VIRTUAL);
        rawTable.setHeaderVisible(true);
        rawTable.setLinesVisible(false);
        rawTable.setFont(nFont);

        final TableLayout layout = new TableLayout();
        rawTable.setLayout(layout);

        createColumns(rawTable, layout);
        createPaintListener(rawTable);

        table = new TableViewer(rawTable) {
            protected Widget doFindItem(final Object element) {
                return element != null ? ((SWTCommit) element).widget : null;
            }

            protected void mapElement(final Object element, final Widget item) {
                ((SWTCommit) element).widget = item;
            }
        };
        table.setLabelProvider(new GraphLabelProvider());
        table.setContentProvider(new GraphContentProvider());
        renderer = new SWTPlotRenderer(rawTable.getDisplay());

        clipboard = new Clipboard(rawTable.getDisplay());
        rawTable.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(final DisposeEvent e) {
                clipboard.dispose();
            }
        });

        final IAction selectAll = createStandardAction(ActionFactory.SELECT_ALL);
        copy = createStandardAction(ActionFactory.COPY);

        table.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                copy.setEnabled(canDoCopy());
            }
        });

        getControl().addFocusListener(new FocusListener() {
            public void focusLost(FocusEvent e) {
                site.getActionBars().setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), null);
                site.getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), null);
                site.getActionBars().updateActionBars();
            }

            public void focusGained(FocusEvent e) {
                site.getActionBars().setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), selectAll);
                site.getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), copy);
                site.getActionBars().updateActionBars();
            }
        });

        getTableView().addOpenListener(new IOpenListener() {
            public void open(OpenEvent event) {
                if (input == null || !input.isSingleFile()) {
                    return;
                }

                ICommandService srv = (ICommandService) site.getService(ICommandService.class);
                IHandlerService hsrv = (IHandlerService) site.getService(IHandlerService.class);
                Command cmd = srv.getCommand(HistoryViewCommands.SHOWVERSIONS);
                Parameterization[] parms;
                if (Activator.getDefault().getPreferenceStore()
                        .getBoolean(UIPreferences.RESOURCEHISTORY_COMPARE_MODE)) {
                    try {
                        IParameter parm = cmd.getParameter(HistoryViewCommands.COMPARE_MODE_PARAM);
                        parms = new Parameterization[] { new Parameterization(parm, Boolean.TRUE.toString()) };
                    } catch (NotDefinedException e) {
                        Activator.handleError(e.getMessage(), e, true);
                        parms = null;
                    }
                } else
                    parms = null;
                ParameterizedCommand pcmd = new ParameterizedCommand(cmd, parms);
                try {
                    hsrv.executeCommandInContext(pcmd, null, hsrv.getCurrentState());
                } catch (Exception e) {
                    Activator.handleError(e.getMessage(), e, true);
                }
            }
        });

        Control c = getControl();
        c.setMenu(menuMgr.createContextMenu(c));
        c.addMenuDetectListener(menuListener = new MenuListener(menuMgr, getTableView(), site, copy));
    }

    Control getControl() {
        return table.getControl();
    }

    void selectCommit(final RevCommit c) {
        table.setSelection(new StructuredSelection(c));
        table.reveal(c);
    }

    void addSelectionChangedListener(final ISelectionChangedListener l) {
        table.addPostSelectionChangedListener(l);
    }

    void removeSelectionChangedListener(final ISelectionChangedListener l) {
        table.removePostSelectionChangedListener(l);
    }

    private boolean canDoCopy() {
        return !table.getSelection().isEmpty();
    }

    @SuppressWarnings("unchecked")
    private void doCopy() {
        final ISelection s = table.getSelection();
        if (s.isEmpty() || !(s instanceof IStructuredSelection))
            return;
        final IStructuredSelection iss = (IStructuredSelection) s;
        final Iterator<PlotCommit> itr = iss.iterator();
        final StringBuilder r = new StringBuilder();
        while (itr.hasNext()) {
            final PlotCommit d = itr.next();
            if (r.length() > 0)
                r.append(LINESEP);
            r.append(d.getId().name());
        }

        clipboard.setContents(new Object[] { r.toString() }, new Transfer[] { TextTransfer.getInstance() },
                DND.CLIPBOARD);
    }

    void setInput(final RevFlag hFlag, final SWTCommitList list, final SWTCommit[] asArray,
            HistoryPageInput input) {
        this.input = input;
        menuListener.setInput(input);
        final SWTCommitList oldList = allCommits;
        highlight = hFlag;
        allCommits = list;
        table.setInput(asArray);
        if (asArray != null && asArray.length > 0) {
            if (oldList != list)
                selectCommit(asArray[0]);
        } else {
            table.getTable().deselectAll();
        }
    }

    private void createColumns(final Table rawTable, final TableLayout layout) {
        final TableColumn graph = new TableColumn(rawTable, SWT.NONE);
        graph.setResizable(true);
        graph.setText(""); //$NON-NLS-1$
        graph.setWidth(250);
        layout.addColumnData(new ColumnWeightData(20, true));

        final TableColumn author = new TableColumn(rawTable, SWT.NONE);
        author.setResizable(true);
        author.setText(UIText.HistoryPage_authorColumn);
        author.setWidth(250);
        layout.addColumnData(new ColumnWeightData(10, true));

        final TableColumn date = new TableColumn(rawTable, SWT.NONE);
        date.setResizable(true);
        date.setText(UIText.HistoryPage_dateColumn);
        date.setWidth(250);
        layout.addColumnData(new ColumnWeightData(5, true));

        final TableColumn commitId = new TableColumn(rawTable, SWT.NONE);
        commitId.setResizable(true);
        commitId.setText(UIText.CommitGraphTable_CommitId);
        commitId.setWidth(100);
        layout.addColumnData(new ColumnWeightData(5, true));

        final TableColumn committer = new TableColumn(rawTable, SWT.NONE);
        committer.setResizable(true);
        committer.setText(UIText.CommitGraphTable_Committer);
        committer.setWidth(100);
        layout.addColumnData(new ColumnWeightData(5, true));
    }

    private void createPaintListener(final Table rawTable) {
        // Tell SWT we will completely handle painting for some columns.
        //
        rawTable.addListener(SWT.EraseItem, new Listener() {
            public void handleEvent(final Event event) {
                if (0 <= event.index && event.index <= 4)
                    event.detail &= ~SWT.FOREGROUND;
            }
        });

        rawTable.addListener(SWT.PaintItem, new Listener() {
            public void handleEvent(final Event event) {
                doPaint(event);
            }
        });
    }

    void doPaint(final Event event) {
        final RevCommit c = (RevCommit) ((TableItem) event.item).getData();
        if (highlight != null && c.has(highlight))
            event.gc.setFont(hFont);
        else
            event.gc.setFont(nFont);

        if (event.index == 0) {
            renderer.paint(event);
            return;
        }

        final ITableLabelProvider lbl;
        final String txt;

        lbl = (ITableLabelProvider) table.getLabelProvider();
        txt = lbl.getColumnText(c, event.index);

        final Point textsz = event.gc.textExtent(txt);
        final int texty = (event.height - textsz.y) / 2;
        event.gc.drawString(txt, event.x, event.y + texty, true);
    }

    /**
     * Returns the SWT TableView of this CommitGraphTable.
     *
     * @return Table the SWT Table
     */
    public TableViewer getTableView() {
        return table;
    }

    private IAction createStandardAction(final ActionFactory af) {
        final String text = af.create(PlatformUI.getWorkbench().getActiveWorkbenchWindow()).getText();
        IAction action = new Action() {

            @Override
            public String getActionDefinitionId() {
                return af.getCommandId();
            }

            @Override
            public String getId() {
                return af.getId();
            }

            @Override
            public String getText() {
                return text;
            }

            @Override
            public void run() {
                if (af == ActionFactory.SELECT_ALL) {
                    table.getTable().selectAll();
                }
                if (af == ActionFactory.COPY) {
                    doCopy();
                }
            }
        };
        return action;
    }

    private final static class MenuListener implements MenuDetectListener {

        private final MenuManager popupMgr;

        private final ISelectionProvider selectionProvider;

        private final IPageSite site;

        private final IAction copyAction;

        private HistoryPageInput input;

        MenuListener(MenuManager menuManager, ISelectionProvider selectionProvider, IPageSite site,
                IAction copyAction) {
            this.popupMgr = menuManager;
            this.selectionProvider = selectionProvider;
            this.site = site;
            this.copyAction = copyAction;
        }

        public void setInput(HistoryPageInput input) {
            this.input = input;
        }

        public void menuDetected(MenuDetectEvent e) {
            popupMgr.removeAll();

            int selectionSize = ((IStructuredSelection) selectionProvider.getSelection()).size();

            if (input.isSingleFile()) {
                if (selectionSize == 1)
                    if (input.getSingleFile() instanceof IResource)
                        popupMgr.add(getCommandContributionItem(HistoryViewCommands.COMPARE_WITH_TREE,
                                UIText.GitHistoryPage_CompareWithWorkingTreeMenuMenuLabel));
                    else
                        popupMgr.add(getCommandContributionItem(HistoryViewCommands.COMPARE_WITH_TREE,
                                UIText.GitHistoryPage_CompareWithCurrentHeadMenu));
                else if (selectionSize == 2)
                    popupMgr.add(getCommandContributionItem(HistoryViewCommands.COMPARE_VERSIONS,
                            UIText.GitHistoryPage_CompareWithEachOtherMenuLabel));
                if (selectionSize > 0) {
                    popupMgr.add(getCommandContributionItem(HistoryViewCommands.OPEN,
                            UIText.GitHistoryPage_OpenMenuLabel));
                    popupMgr.add(getCommandContributionItem(HistoryViewCommands.OPEN_IN_TEXT_EDITOR,
                            UIText.GitHistoryPage_OpenInTextEditorLabel));
                }
            }

            if (selectionSize == 1) {
                popupMgr.add(new Separator());
                popupMgr.add(getCommandContributionItem(HistoryViewCommands.CHECKOUT,
                        UIText.GitHistoryPage_CheckoutMenuLabel));
                popupMgr.add(getCommandContributionItem(HistoryViewCommands.CREATE_BRANCH,
                        UIText.GitHistoryPage_CreateBranchMenuLabel));
                popupMgr.add(getCommandContributionItem(HistoryViewCommands.CREATE_TAG,
                        UIText.GitHistoryPage_CreateTagMenuLabel));
                popupMgr.add(getCommandContributionItem(HistoryViewCommands.CREATE_PATCH,
                        UIText.GitHistoryPage_CreatePatchMenuLabel));
                popupMgr.add(getCommandContributionItem(HistoryViewCommands.CHERRYPICK,
                        UIText.GitHistoryPage_cherryPickMenuItem));
                popupMgr.add(new Separator());

                MenuManager resetManager = new MenuManager(UIText.GitHistoryPage_ResetMenuLabel, UIIcons.RESET,
                        "Reset"); //$NON-NLS-1$

                popupMgr.add(resetManager);

                Map<String, String> parameters = new HashMap<String, String>();
                parameters.put(HistoryViewCommands.RESET_MODE, "Soft"); //$NON-NLS-1$
                resetManager.add(getCommandContributionItem(HistoryViewCommands.RESET,
                        UIText.GitHistoryPage_ResetSoftMenuLabel, parameters));
                parameters = new HashMap<String, String>();
                parameters.put(HistoryViewCommands.RESET_MODE, "Mixed"); //$NON-NLS-1$
                resetManager.add(getCommandContributionItem(HistoryViewCommands.RESET,
                        UIText.GitHistoryPage_ResetMixedMenuLabel, parameters));
                parameters = new HashMap<String, String>();
                parameters.put(HistoryViewCommands.RESET_MODE, "Hard"); //$NON-NLS-1$
                resetManager.add(getCommandContributionItem(HistoryViewCommands.RESET,
                        UIText.GitHistoryPage_ResetHardMenuLabel, parameters));
            }
            popupMgr.add(new Separator());

            MenuManager quickDiffManager = new MenuManager(UIText.GitHistoryPage_QuickdiffMenuLabel, null,
                    "Quickdiff"); //$NON-NLS-1$

            popupMgr.add(quickDiffManager);

            quickDiffManager.add(getCommandContributionItem(HistoryViewCommands.SET_QUICKDIFF_BASELINE,
                    UIText.GitHistoryPage_SetAsBaselineMenuLabel));

            Map<String, String> parameters = new HashMap<String, String>();
            parameters.put(HistoryViewCommands.BASELINE_TARGET, "HEAD"); //$NON-NLS-1$
            quickDiffManager.add(getCommandContributionItem(HistoryViewCommands.RESET_QUICKDIFF_BASELINE,
                    UIText.GitHistoryPage_ResetBaselineToHeadMenuLabel, parameters));

            parameters = new HashMap<String, String>();
            parameters.put(HistoryViewCommands.BASELINE_TARGET, "HEAD^1"); //$NON-NLS-1$
            quickDiffManager.add(getCommandContributionItem(HistoryViewCommands.RESET_QUICKDIFF_BASELINE,
                    UIText.GitHistoryPage_ResetBaselineToParentOfHeadMenuLabel, parameters));

            // copy and such after additions
            popupMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
            popupMgr.add(copyAction);
            popupMgr.add(new Separator());
        }

        private CommandContributionItem getCommandContributionItem(String commandId, String menuLabel) {
            CommandContributionItemParameter parameter = new CommandContributionItemParameter(site, commandId,
                    commandId, CommandContributionItem.STYLE_PUSH);
            parameter.label = menuLabel;
            return new CommandContributionItem(parameter);
        }

        private CommandContributionItem getCommandContributionItem(String commandId, String menuLabel,
                Map<String, String> parameters) {
            CommandContributionItemParameter parameter = new CommandContributionItemParameter(site, commandId,
                    commandId, CommandContributionItem.STYLE_PUSH);
            parameter.label = menuLabel;
            parameter.parameters = parameters;
            return new CommandContributionItem(parameter);
        }
    }
}