gitLink.GLinkTreeViewer.java Source code

Java tutorial

Introduction

Here is the source code for gitLink.GLinkTreeViewer.java

Source

/*******************************************************************************
 * Copyright (C) 2010, Mark Farnsworth <farnsworth2008@gmail.com>
 * <p>
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU GENERAL PUBLIC LICENSE which accompanies
 * this distribution, and is available at
 * http://www.gnu.org/licenses/gpl-3.0.txt
 *******************************************************************************/
package gitLink;

import java.io.File;
import java.util.Observable;
import java.util.Observer;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPartSite;

/**
 * A Tree view for Git Status.
 * 
 * @author Mark Farnsworth <farnsworth2008@gmail.com>
 */
final class GLinkTreeViewer extends TreeViewer
        implements Observer, IMenuListener, ITreeContentProvider, ShellListener {
    /**
     * Get label for an object
     */
    class ViewLabelProvider extends LabelProvider {
        @Override
        public Image getImage(final Object obj) {
            return ((GLinkNode) obj).image();
        }
    }

    /**
     * Action to open a repository (currently git gui)
     */
    private final IAction actionOpen;
    /**
     * Action to refresh
     */
    private final IAction actionRefresh;
    /**
     * Action to show history (currently gitk)
     */
    private final IAction actionShowHistory;
    /**
     * Our menu manager
     */
    private final MenuManager menuManager;
    /**
     * Our resource workspace
     */
    private final IWorkspace resourceWorkspace;
    private final Shell shell;
    /**
     * Our view
     */
    final GLinkStatusView view;
    /**
     * Our workspace
     */
    final GLinkWorkspace workspace;
    private final IAction actionStage;
    private final IAction actionUnstage;
    private final IAction actionDiscard;

    /**
     * Create a treeviewer for git status
     * 
     * @param parent
     * @param gLinkStatusView
     */
    GLinkTreeViewer(final GLinkStatusView gLinkStatusView, final Composite parent) {
        super(parent);
        view = gLinkStatusView;
        final Control control = getControl();
        final IWorkbenchPartSite site = view.getSite();
        final IViewSite viewSite = view.getViewSite();
        shell = site.getWorkbenchWindow().getShell();
        shell.addShellListener(this);
        actionOpen = newOpenAction();
        actionStage = newStageAction();
        actionDiscard = newDiscardAction();
        actionUnstage = newUnstageAction();
        actionRefresh = newRefreshAction();
        actionShowHistory = newHistoryAction();
        menuManager = new MenuManager("#PopupMenu");
        workspace = new GLinkWorkspace();
        resourceWorkspace = ResourcesPlugin.getWorkspace();
        workspace.addObserver(this);
        resourceWorkspace.addResourceChangeListener(workspace);
        menuManager.setRemoveAllWhenShown(true);
        menuManager.addMenuListener(this);
        final Menu menu = menuManager.createContextMenu(control);
        setContentProvider(this);
        setLabelProvider(new ViewLabelProvider());
        setInput(viewSite);
        control.setMenu(menu);
        site.registerContextMenu(menuManager, this);
        final IActionBars bars = viewSite.getActionBars();
        bars.getToolBarManager().add(newGitAction());
        bars.getToolBarManager().add(actionRefresh);
        workspace.startUpdateJob(1000 * 5);
    }

    /**
     * Disconnect so we can safely dispose
     * <p>
     * It is critical that we unlink "live" connections here. Specifically we
     * need to stop listening for events and it is a good idea to stop observing
     * the model.
     */
    public void dispose() {
        shell.removeShellListener(this);
        workspace.deleteObserver(this);
        resourceWorkspace.removeResourceChangeListener(workspace);
        menuManager.removeMenuListener(this);
    }

    /**
     * Do the refresh by clearing our model of the workspace and then starting a
     * new update job.
     */
    void doRefreshAction() {
        workspace.clear();
        workspace.startUpdateJob(100);
    }

    public Object[] getChildren(final Object arg0) {
        return ((GLinkNode) arg0).children().values().toArray();
    }

    public Object[] getElements(final Object arg0) {
        return workspace.getObjects();
    }

    public Object getParent(final Object arg0) {
        return ((GLinkNode) arg0).parent();
    }

    public boolean hasChildren(final Object arg0) {
        return ((GLinkNode) arg0).children().size() > 0;
    }

    public void inputChanged(final Viewer arg0, final Object arg1, final Object arg2) {
    }

    public void menuAboutToShow(final IMenuManager manager) {
        final ISelection s = view.viewer.getSelection();
        manager.add(actionRefresh);
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
        if (s instanceof ITreeSelection) {
            final ITreeSelection ts = (ITreeSelection) s;
            manager.add(actionOpen);
            manager.add(actionShowHistory);
            final Object fe = ts.getFirstElement();
            if (fe instanceof GLinkNode) {
                final GLinkNode node = (GLinkNode) fe;
                if (node.image() == GLinkPlugin.im_add)
                    manager.add(actionStage);
                else if (node.image() == GLinkPlugin.im_modified) {
                    manager.add(actionStage);
                    manager.add(actionDiscard);
                } else if (node.image() == GLinkPlugin.im_deleted)
                    manager.add(actionStage);
                else if (node.image() == GLinkPlugin.im_indexedAdd)
                    manager.add(actionUnstage);
                else if (node.image() == GLinkPlugin.im_indexedModified)
                    manager.add(actionUnstage);
                else if (node.image() == GLinkPlugin.im_indexedRename)
                    manager.add(actionUnstage);
                else if (node.image() == GLinkPlugin.im_indexedDeleted)
                    manager.add(actionUnstage);
            }
        }
    }

    private IAction newDiscardAction() {
        final Action n = new Action() {
            @Override
            public void run() {
                try {
                    final ISelection sel = view.viewer.getSelection();
                    if (sel instanceof StructuredSelection) {
                        final StructuredSelection ss = (StructuredSelection) sel;
                        final GLinkNode item = (GLinkNode) ss.getFirstElement();
                        GLinkNode node = item;
                        while (!(node instanceof GLinkRepositoryNode))
                            node = node.parent();
                        final GLinkRepositoryNode repo = (GLinkRepositoryNode) node;
                        final File file = repo.file();
                        final ProcessBuilder builder = new ProcessBuilder("git", "checkout", "--", item.text());
                        builder.directory(file);
                        builder.start();
                        doRefreshAction();
                    }
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        n.setText("Discard");
        n.setImageDescriptor(GLinkPlugin.id_gitLink);
        return n;
    }

    /**
     * @return Action for launching git
     */
    private IAction newGitAction() {
        final Action n = new Action() {
            @Override
            public void run() {
                try {
                    final ProcessBuilder builder = new ProcessBuilder("git", "gui");
                    builder.start();
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        n.setText("Open \"git gui\"");
        n.setImageDescriptor(GLinkPlugin.id_gitLink);
        return n;
    }

    /**
     * @return Action to launch GITK
     */
    private IAction newHistoryAction() {
        final Action n = new Action() {
            @Override
            public void run() {
                try {
                    final ISelection sel = view.viewer.getSelection();
                    final ProcessBuilder builder = new ProcessBuilder("gitk");
                    final StructuredSelection ss = (StructuredSelection) sel;
                    final GLinkRepositoryNode item = (GLinkRepositoryNode) ss.getFirstElement();
                    final File file = item.file();
                    builder.directory(file);
                    builder.start();
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        n.setText("Show history using \"gitk\"");
        n.setImageDescriptor(GLinkPlugin.id_gitLink);
        return n;
    }

    /**
     * @return Action to open git gui
     */
    private Action newOpenAction() {
        final Action n = new Action() {
            @Override
            public void run() {
                try {
                    final ISelection sel = view.viewer.getSelection();
                    final ProcessBuilder builder = new ProcessBuilder("git", "gui");
                    if (sel instanceof StructuredSelection) {
                        final StructuredSelection ss = (StructuredSelection) sel;
                        GLinkNode node = (GLinkNode) ss.getFirstElement();
                        while (!(node instanceof GLinkRepositoryNode))
                            node = node.parent();
                        final GLinkRepositoryNode item = (GLinkRepositoryNode) node;
                        final File file = item.file();
                        builder.directory(file);
                    }
                    builder.start();
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        n.setText("Open with \"git gui\"");
        n.setImageDescriptor(GLinkPlugin.id_gitLink);
        return n;
    }

    /**
     * @return Refresh action
     */
    private Action newRefreshAction() {
        final Action n = new Action() {
            @Override
            public void run() {
                doRefreshAction();
            }
        };
        n.setText("Refresh");
        n.setToolTipText("Run \"git status\" for each git folder");
        n.setImageDescriptor(GLinkPlugin.id_refresh);
        return n;
    }

    private IAction newStageAction() {
        final Action n = new Action() {
            @Override
            public void run() {
                try {
                    final ISelection sel = view.viewer.getSelection();
                    if (sel instanceof StructuredSelection) {
                        final StructuredSelection ss = (StructuredSelection) sel;
                        final GLinkNode item = (GLinkNode) ss.getFirstElement();
                        GLinkNode node = item;
                        while (!(node instanceof GLinkRepositoryNode))
                            node = node.parent();
                        final GLinkRepositoryNode repo = (GLinkRepositoryNode) node;
                        final File file = repo.file();
                        final ProcessBuilder builder = new ProcessBuilder("git", "add", "-A", item.text());
                        builder.directory(file);
                        builder.start();
                        doRefreshAction();
                    }
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        n.setText("Stage");
        n.setImageDescriptor(GLinkPlugin.id_gitLink);
        return n;
    }

    private IAction newUnstageAction() {
        final Action n = new Action() {
            @Override
            public void run() {
                try {
                    final ISelection sel = view.viewer.getSelection();
                    if (sel instanceof StructuredSelection) {
                        final StructuredSelection ss = (StructuredSelection) sel;
                        final GLinkNode item = (GLinkNode) ss.getFirstElement();
                        GLinkNode node = item;
                        while (!(node instanceof GLinkRepositoryNode))
                            node = node.parent();
                        final GLinkRepositoryNode repo = (GLinkRepositoryNode) node;
                        final File file = repo.file();
                        final ProcessBuilder builder = new ProcessBuilder("git", "reset", item.text());
                        builder.directory(file);
                        builder.start();
                        doRefreshAction();
                    }
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        n.setText("Unstage");
        n.setImageDescriptor(GLinkPlugin.id_gitLink);
        return n;
    }

    @Override
    public void shellActivated(final ShellEvent arg0) {
        doRefreshAction();
    }

    @Override
    public void shellClosed(final ShellEvent arg0) {
    }

    @Override
    public void shellDeactivated(final ShellEvent arg0) {
    }

    @Override
    public void shellDeiconified(final ShellEvent arg0) {
    }

    @Override
    public void shellIconified(final ShellEvent arg0) {
    }

    /**
     * Process an update
     */
    public void update(final Observable arg0, final Object arg1) {
        final Runnable refresh = new Runnable() {
            public void run() {
                view.viewer.refresh(true);
                view.viewer.expandAll();
            }
        };
        Display.getDefault().asyncExec(refresh);
    }
}