Java tutorial
/******************************************************************************* * 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); } }