Git Repositories View: add CollapseAll action
[egit/spearce.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / repository / RepositoriesView.java
blob629a232611307999dd4fbb07405047a211a586ab
1 /*******************************************************************************
2 * Copyright (c) 2010 SAP AG.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 * Contributors:
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal.repository;
13 import java.io.File;
14 import java.io.IOException;
15 import java.lang.reflect.InvocationTargetException;
16 import java.net.URISyntaxException;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Set;
23 import java.util.StringTokenizer;
24 import java.util.TreeSet;
26 import org.eclipse.core.filesystem.EFS;
27 import org.eclipse.core.filesystem.IFileStore;
28 import org.eclipse.core.resources.IProject;
29 import org.eclipse.core.resources.IProjectDescription;
30 import org.eclipse.core.resources.IResource;
31 import org.eclipse.core.resources.IWorkspace;
32 import org.eclipse.core.resources.IWorkspaceRunnable;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.CoreException;
35 import org.eclipse.core.runtime.IAdaptable;
36 import org.eclipse.core.runtime.IPath;
37 import org.eclipse.core.runtime.IProgressMonitor;
38 import org.eclipse.core.runtime.IStatus;
39 import org.eclipse.core.runtime.NullProgressMonitor;
40 import org.eclipse.core.runtime.Path;
41 import org.eclipse.core.runtime.Status;
42 import org.eclipse.core.runtime.SubProgressMonitor;
43 import org.eclipse.core.runtime.jobs.IJobChangeEvent;
44 import org.eclipse.core.runtime.jobs.Job;
45 import org.eclipse.core.runtime.jobs.JobChangeAdapter;
46 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
47 import org.eclipse.core.runtime.preferences.InstanceScope;
48 import org.eclipse.egit.core.op.BranchOperation;
49 import org.eclipse.egit.core.op.ConnectProviderOperation;
50 import org.eclipse.egit.core.project.RepositoryMapping;
51 import org.eclipse.egit.ui.Activator;
52 import org.eclipse.egit.ui.UIIcons;
53 import org.eclipse.egit.ui.UIText;
54 import org.eclipse.egit.ui.internal.clone.GitCloneWizard;
55 import org.eclipse.egit.ui.internal.clone.GitCreateProjectViaWizardWizard;
56 import org.eclipse.egit.ui.internal.repository.RepositoryTreeNode.RepositoryTreeNodeType;
57 import org.eclipse.jface.action.Action;
58 import org.eclipse.jface.action.IAction;
59 import org.eclipse.jface.dialogs.MessageDialog;
60 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
61 import org.eclipse.jface.operation.IRunnableWithProgress;
62 import org.eclipse.jface.viewers.IOpenListener;
63 import org.eclipse.jface.viewers.ISelection;
64 import org.eclipse.jface.viewers.ISelectionChangedListener;
65 import org.eclipse.jface.viewers.ISelectionProvider;
66 import org.eclipse.jface.viewers.IStructuredSelection;
67 import org.eclipse.jface.viewers.ITreeContentProvider;
68 import org.eclipse.jface.viewers.OpenEvent;
69 import org.eclipse.jface.viewers.SelectionChangedEvent;
70 import org.eclipse.jface.viewers.StructuredSelection;
71 import org.eclipse.jface.viewers.TreeViewer;
72 import org.eclipse.jface.window.Window;
73 import org.eclipse.jface.wizard.Wizard;
74 import org.eclipse.jface.wizard.WizardDialog;
75 import org.eclipse.jgit.lib.Constants;
76 import org.eclipse.jgit.lib.Ref;
77 import org.eclipse.jgit.lib.RefUpdate;
78 import org.eclipse.jgit.lib.Repository;
79 import org.eclipse.jgit.lib.RepositoryConfig;
80 import org.eclipse.jgit.transport.RemoteConfig;
81 import org.eclipse.osgi.util.NLS;
82 import org.eclipse.swt.SWT;
83 import org.eclipse.swt.dnd.Clipboard;
84 import org.eclipse.swt.dnd.TextTransfer;
85 import org.eclipse.swt.dnd.Transfer;
86 import org.eclipse.swt.events.MenuDetectEvent;
87 import org.eclipse.swt.events.MenuDetectListener;
88 import org.eclipse.swt.events.SelectionAdapter;
89 import org.eclipse.swt.events.SelectionEvent;
90 import org.eclipse.swt.graphics.Point;
91 import org.eclipse.swt.widgets.Composite;
92 import org.eclipse.swt.widgets.Display;
93 import org.eclipse.swt.widgets.Menu;
94 import org.eclipse.swt.widgets.MenuItem;
95 import org.eclipse.swt.widgets.TreeItem;
96 import org.eclipse.ui.IEditorInput;
97 import org.eclipse.ui.IEditorPart;
98 import org.eclipse.ui.IFileEditorInput;
99 import org.eclipse.ui.IPageLayout;
100 import org.eclipse.ui.ISelectionListener;
101 import org.eclipse.ui.ISelectionService;
102 import org.eclipse.ui.IViewPart;
103 import org.eclipse.ui.IWorkbenchPart;
104 import org.eclipse.ui.PartInitException;
105 import org.eclipse.ui.PlatformUI;
106 import org.eclipse.ui.editors.text.EditorsUI;
107 import org.eclipse.ui.ide.FileStoreEditorInput;
108 import org.eclipse.ui.ide.IDE;
109 import org.eclipse.ui.part.IShowInTarget;
110 import org.eclipse.ui.part.ShowInContext;
111 import org.eclipse.ui.part.ViewPart;
112 import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
113 import org.eclipse.ui.views.properties.IPropertySheetPage;
114 import org.eclipse.ui.views.properties.PropertySheet;
115 import org.eclipse.ui.views.properties.PropertySheetPage;
116 import org.osgi.service.prefs.BackingStoreException;
120 * The Git Repositories view.
121 * <p>
122 * This keeps track of a bunch of local directory names each of which represent
123 * a Git Repository. This list is stored in some Preferences object and used to
124 * build the tree in the view.
125 * <p>
126 * Implements {@link ISelectionProvider} in order to integrate with the
127 * Properties view.
128 * <p>
129 * TODO
130 * <li>Clarification whether to show projects, perhaps configurable switch</li>
133 public class RepositoriesView extends ViewPart implements ISelectionProvider,
134 IShowInTarget {
136 /** The view ID */
137 public static final String VIEW_ID = "org.eclipse.egit.ui.RepositoriesView"; //$NON-NLS-1$
139 // TODO central constants? RemoteConfig ones are private
140 static final String REMOTE = "remote"; //$NON-NLS-1$
142 static final String URL = "url"; //$NON-NLS-1$
144 static final String PUSHURL = "pushurl"; //$NON-NLS-1$
146 static final String FETCH = "fetch"; //$NON-NLS-1$
148 static final String PUSH = "push"; //$NON-NLS-1$
150 private static final String PREFS_DIRECTORIES = "GitRepositoriesView.GitDirectories"; //$NON-NLS-1$
152 private static final String PREFS_SYNCED = "GitRepositoriesView.SyncWithSelection"; //$NON-NLS-1$
154 private final List<ISelectionChangedListener> selectionListeners = new ArrayList<ISelectionChangedListener>();
156 private ISelection currentSelection = new StructuredSelection();
158 private Job scheduledJob;
160 private TreeViewer tv;
162 private IAction importAction;
164 private IAction addAction;
166 private IAction refreshAction;
168 private IAction linkWithSelectionAction;
170 private static List<String> getDirs() {
171 List<String> resultStrings = new ArrayList<String>();
172 String dirs = getPrefs().get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$
173 if (dirs != null && dirs.length() > 0) {
174 StringTokenizer tok = new StringTokenizer(dirs, File.pathSeparator);
175 while (tok.hasMoreTokens()) {
176 String dirName = tok.nextToken();
177 File testFile = new File(dirName);
178 if (testFile.exists()) {
179 resultStrings.add(dirName);
183 Collections.sort(resultStrings);
184 return resultStrings;
187 private static void removeDir(File file) {
189 String dir;
190 try {
191 dir = file.getCanonicalPath();
192 } catch (IOException e1) {
193 dir = file.getAbsolutePath();
196 IEclipsePreferences prefs = getPrefs();
198 TreeSet<String> resultStrings = new TreeSet<String>();
199 String dirs = prefs.get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$
200 if (dirs != null && dirs.length() > 0) {
201 StringTokenizer tok = new StringTokenizer(dirs, File.pathSeparator);
202 while (tok.hasMoreTokens()) {
203 String dirName = tok.nextToken();
204 File testFile = new File(dirName);
205 if (testFile.exists()) {
206 try {
207 resultStrings.add(testFile.getCanonicalPath());
208 } catch (IOException e) {
209 resultStrings.add(testFile.getAbsolutePath());
215 if (resultStrings.remove(dir)) {
216 StringBuilder sb = new StringBuilder();
217 for (String gitDirString : resultStrings) {
218 sb.append(gitDirString);
219 sb.append(File.pathSeparatorChar);
222 prefs.put(PREFS_DIRECTORIES, sb.toString());
223 try {
224 prefs.flush();
225 } catch (BackingStoreException e) {
226 IStatus error = new Status(IStatus.ERROR, Activator
227 .getPluginId(), e.getMessage(), e);
228 Activator.getDefault().getLog().log(error);
234 @Override
235 public Object getAdapter(Class adapter) {
236 // integrate with Properties view
237 if (adapter == IPropertySheetPage.class) {
238 PropertySheetPage page = new PropertySheetPage();
239 page
240 .setPropertySourceProvider(new RepositoryPropertySourceProvider(
241 page));
242 return page;
245 return super.getAdapter(adapter);
248 @Override
249 public void createPartControl(Composite parent) {
250 tv = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
251 tv.setContentProvider(new RepositoriesViewContentProvider());
252 // the label provider registers itself
253 new RepositoriesViewLabelProvider(tv);
255 getSite().setSelectionProvider(this);
257 tv.addSelectionChangedListener(new ISelectionChangedListener() {
259 public void selectionChanged(SelectionChangedEvent event) {
261 IStructuredSelection ssel = (IStructuredSelection) event
262 .getSelection();
263 if (ssel.size() == 1) {
264 setSelection(new StructuredSelection(ssel.getFirstElement()));
265 } else {
266 setSelection(new StructuredSelection());
271 tv.addOpenListener(new IOpenListener() {
272 public void open(OpenEvent event) {
273 IStructuredSelection selection = (IStructuredSelection) event
274 .getSelection();
275 if (selection.isEmpty()) {
276 // nothing selected, ignore
277 return;
280 Object element = selection.getFirstElement();
281 ITreeContentProvider contentProvider = (ITreeContentProvider) tv
282 .getContentProvider();
283 if (contentProvider.hasChildren(element)) {
284 // this element has children, expand/collapse it
285 tv.setExpandedState(element, !tv.getExpandedState(element));
286 } else {
287 Object[] selectionArray = selection.toArray();
288 for (Object selectedElement : selectionArray) {
289 RepositoryTreeNode node = (RepositoryTreeNode) selectedElement;
290 // if any of the selected elements are not files, ignore
291 // the open request
292 if (node.getType() != RepositoryTreeNodeType.FILE
293 && node.getType() != RepositoryTreeNodeType.REF) {
294 return;
298 // open the files the user has selected
299 for (Object selectedElement : selectionArray) {
300 RepositoryTreeNode node = (RepositoryTreeNode) selectedElement;
301 if (node.getType() == RepositoryTreeNodeType.FILE)
302 openFile((File) node.getObject());
303 else if (node.getType() == RepositoryTreeNodeType.REF) {
304 Ref ref = (Ref) node.getObject();
305 if (ref.getName().startsWith(Constants.R_HEADS)
306 || ref.getName().startsWith(
307 Constants.R_REMOTES))
308 checkoutBranch(node, ref.getName());
315 addContextMenu();
317 addActionsToToolbar();
319 scheduleRefresh();
321 ISelectionService srv = (ISelectionService) getSite().getService(
322 ISelectionService.class);
323 srv.addPostSelectionListener(new ISelectionListener() {
325 public void selectionChanged(IWorkbenchPart part,
326 ISelection selection) {
328 // if the "link with selection" toggle is off, we're done
329 if (linkWithSelectionAction == null
330 || !linkWithSelectionAction.isChecked())
331 return;
333 // this may happen if we switch between editors
334 if (part instanceof IEditorPart) {
335 IEditorInput input = ((IEditorPart) part).getEditorInput();
336 if (input instanceof IFileEditorInput)
337 reactOnSelection(new StructuredSelection(
338 ((IFileEditorInput) input).getFile()));
340 } else {
341 reactOnSelection(selection);
348 private void reactOnSelection(ISelection selection) {
349 if (selection instanceof StructuredSelection) {
350 StructuredSelection ssel = (StructuredSelection) selection;
351 if (ssel.size() != 1)
352 return;
353 if (ssel.getFirstElement() instanceof IResource) {
354 showResource((IResource) ssel.getFirstElement());
356 if (ssel.getFirstElement() instanceof IAdaptable) {
357 IResource adapted = (IResource) ((IAdaptable) ssel
358 .getFirstElement()).getAdapter(IResource.class);
359 if (adapted != null)
360 showResource(adapted);
365 private void addContextMenu() {
366 tv.getTree().addMenuDetectListener(new MenuDetectListener() {
368 public void menuDetected(MenuDetectEvent e) {
370 tv.getTree().setMenu(null);
371 Menu men = new Menu(tv.getTree());
373 TreeItem testItem = tv.getTree().getItem(
374 tv.getTree().toControl(new Point(e.x, e.y)));
375 if (testItem == null) {
376 addMenuItemsForPanel(men);
377 } else {
378 addMenuItemsForTreeSelection(men);
381 tv.getTree().setMenu(men);
386 private void addMenuItemsForPanel(Menu men) {
388 MenuItem importItem = new MenuItem(men, SWT.PUSH);
389 importItem.setText(UIText.RepositoriesView_ImportRepository_MenuItem);
390 importItem.addSelectionListener(new SelectionAdapter() {
392 @Override
393 public void widgetSelected(SelectionEvent e) {
394 importAction.run();
399 MenuItem addItem = new MenuItem(men, SWT.PUSH);
400 addItem.setText(UIText.RepositoriesView_AddRepository_MenuItem);
401 addItem.addSelectionListener(new SelectionAdapter() {
403 @Override
404 public void widgetSelected(SelectionEvent e) {
405 addAction.run();
410 MenuItem refreshItem = new MenuItem(men, SWT.PUSH);
411 refreshItem.setText(refreshAction.getText());
412 refreshItem.addSelectionListener(new SelectionAdapter() {
414 @Override
415 public void widgetSelected(SelectionEvent e) {
416 refreshAction.run();
423 @SuppressWarnings("unchecked")
424 private void addMenuItemsForTreeSelection(Menu men) {
426 final IStructuredSelection sel = (IStructuredSelection) tv
427 .getSelection();
429 boolean importableProjectsOnly = true;
431 for (Object node : sel.toArray()) {
432 RepositoryTreeNode tnode = (RepositoryTreeNode) node;
433 importableProjectsOnly = tnode.getType() == RepositoryTreeNodeType.PROJ;
434 if (!importableProjectsOnly)
435 break;
438 if (importableProjectsOnly) {
439 MenuItem sync = new MenuItem(men, SWT.PUSH);
440 sync.setText(UIText.RepositoriesView_ImportProject_MenuItem);
442 sync.addSelectionListener(new SelectionAdapter() {
444 @Override
445 public void widgetSelected(SelectionEvent e) {
447 IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
449 public void run(IProgressMonitor monitor)
450 throws CoreException {
452 for (Object selected : sel.toArray()) {
453 RepositoryTreeNode<File> projectNode = (RepositoryTreeNode<File>) selected;
454 File file = projectNode.getObject();
456 IProjectDescription pd = ResourcesPlugin
457 .getWorkspace().newProjectDescription(
458 file.getName());
459 IPath locationPath = new Path(file
460 .getAbsolutePath());
462 pd.setLocation(locationPath);
464 ResourcesPlugin.getWorkspace().getRoot()
465 .getProject(pd.getName()).create(pd,
466 monitor);
467 IProject project = ResourcesPlugin
468 .getWorkspace().getRoot().getProject(
469 pd.getName());
470 project.open(monitor);
472 File gitDir = projectNode.getRepository()
473 .getDirectory();
475 ConnectProviderOperation connectProviderOperation = new ConnectProviderOperation(
476 project, gitDir);
477 connectProviderOperation
478 .execute(new SubProgressMonitor(monitor, 20));
485 try {
487 ResourcesPlugin.getWorkspace().run(wsr,
488 ResourcesPlugin.getWorkspace().getRoot(),
489 IWorkspace.AVOID_UPDATE,
490 new NullProgressMonitor());
492 scheduleRefresh();
493 } catch (CoreException e1) {
494 Activator.logError(e1.getMessage(), e1);
502 // from here on, we only deal with single selection
503 if (sel.size() > 1)
504 return;
506 final RepositoryTreeNode node = (RepositoryTreeNode) sel
507 .getFirstElement();
509 if (node.getType() == RepositoryTreeNodeType.REF) {
511 final Ref ref = (Ref) node.getObject();
513 // we don't check out symbolic references
514 if (!ref.isSymbolic()) {
516 MenuItem checkout = new MenuItem(men, SWT.PUSH);
517 checkout.setText(UIText.RepositoriesView_CheckOut_MenuItem);
519 try {
520 if (node.getRepository().getFullBranch().equals(
521 ref.getName())) {
522 // no checkout on current branch
523 checkout.setEnabled(false);
525 } catch (IOException e2) {
526 // ignore
529 checkout.addSelectionListener(new SelectionAdapter() {
531 @Override
532 public void widgetSelected(SelectionEvent e) {
534 checkoutBranch(node, ref.getLeaf().getName());
539 new MenuItem(men, SWT.SEPARATOR);
541 createCreateBranchItem(men, node);
542 createDeleteBranchItem(men, node);
547 if (node.getType() == RepositoryTreeNodeType.LOCALBRANCHES
548 || node.getType() == RepositoryTreeNodeType.REMOTEBRANCHES)
549 createCreateBranchItem(men, node);
551 // for Repository: import existing projects, remove, (delete), open
552 // properties
553 if (node.getType() == RepositoryTreeNodeType.REPO) {
555 final Repository repo = (Repository) node.getObject();
557 // TODO "import existing plug-in" menu item
559 MenuItem remove = new MenuItem(men, SWT.PUSH);
560 remove.setText(UIText.RepositoriesView_Remove_MenuItem);
561 remove.addSelectionListener(new SelectionAdapter() {
563 @Override
564 public void widgetSelected(SelectionEvent e) {
566 List<IProject> projectsToDelete = new ArrayList<IProject>();
567 File workDir = repo.getWorkDir();
568 final IPath wdPath = new Path(workDir.getAbsolutePath());
569 for (IProject prj : ResourcesPlugin.getWorkspace()
570 .getRoot().getProjects()) {
571 if (wdPath.isPrefixOf(prj.getLocation())) {
572 projectsToDelete.add(prj);
576 if (!projectsToDelete.isEmpty()) {
577 boolean confirmed;
578 confirmed = confirmProjectDeletion(projectsToDelete);
579 if (!confirmed) {
580 return;
584 IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
586 public void run(IProgressMonitor monitor)
587 throws CoreException {
589 for (IProject prj : ResourcesPlugin.getWorkspace()
590 .getRoot().getProjects()) {
591 if (wdPath.isPrefixOf(prj.getLocation())) {
592 prj.delete(false, false, monitor);
596 removeDir(repo.getDirectory());
597 scheduleRefresh();
601 try {
602 ResourcesPlugin.getWorkspace().run(wsr,
603 ResourcesPlugin.getWorkspace().getRoot(),
604 IWorkspace.AVOID_UPDATE,
605 new NullProgressMonitor());
606 } catch (CoreException e1) {
607 Activator.logError(e1.getMessage(), e1);
614 // TODO delete does not work because of file locks on .pack-files
615 // Shawn Pearce has added the following thoughts:
617 // Hmm. We probably can't active detect file locks on pack files on
618 // Windows, can we?
619 // It would be nice if we could support a delete, but only if the
620 // repository is
621 // reasonably believed to be not-in-use right now.
623 // Within EGit you might be able to check GitProjectData and its
624 // repositoryCache to
625 // see if the repository is open by this workspace. If it is, then
626 // we know we shouldn't
627 // try to delete it.
629 // Some coding might look like this:
631 // MenuItem deleteRepo = new MenuItem(men, SWT.PUSH);
632 // deleteRepo.setText("Delete");
633 // deleteRepo.addSelectionListener(new SelectionAdapter() {
635 // @Override
636 // public void widgetSelected(SelectionEvent e) {
638 // boolean confirmed = MessageDialog.openConfirm(getSite()
639 // .getShell(), "Confirm",
640 // "This will delete the repository, continue?");
642 // if (!confirmed)
643 // return;
645 // IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
647 // public void run(IProgressMonitor monitor)
648 // throws CoreException {
649 // File workDir = repos.get(0).getRepository()
650 // .getWorkDir();
652 // File gitDir = repos.get(0).getRepository()
653 // .getDirectory();
655 // IPath wdPath = new Path(workDir.getAbsolutePath());
656 // for (IProject prj : ResourcesPlugin.getWorkspace()
657 // .getRoot().getProjects()) {
658 // if (wdPath.isPrefixOf(prj.getLocation())) {
659 // prj.delete(false, false, monitor);
660 // }
661 // }
663 // repos.get(0).getRepository().close();
665 // boolean deleted = deleteRecursively(gitDir, monitor);
666 // if (!deleted) {
667 // MessageDialog.openError(getSite().getShell(),
668 // "Error",
669 // "Could not delete Git Repository");
670 // }
672 // deleted = deleteRecursively(workDir, monitor);
673 // if (!deleted) {
674 // MessageDialog
675 // .openError(getSite().getShell(),
676 // "Error",
677 // "Could not delete Git Working Directory");
678 // }
680 // scheduleRefresh();
681 // }
683 // private boolean deleteRecursively(File fileToDelete,
684 // IProgressMonitor monitor) {
685 // if (fileToDelete.isDirectory()) {
686 // for (File file : fileToDelete.listFiles()) {
687 // if (!deleteRecursively(file, monitor)) {
688 // return false;
689 // }
690 // }
691 // }
692 // monitor.setTaskName(fileToDelete.getAbsolutePath());
693 // boolean deleted = fileToDelete.delete();
694 // if (!deleted) {
695 // System.err.println("Could not delete "
696 // + fileToDelete.getAbsolutePath());
697 // }
698 // return deleted;
699 // }
700 // };
702 // try {
703 // ResourcesPlugin.getWorkspace().run(wsr,
704 // ResourcesPlugin.getWorkspace().getRoot(),
705 // IWorkspace.AVOID_UPDATE,
706 // new NullProgressMonitor());
707 // } catch (CoreException e1) {
708 // // TODO Exception handling
709 // e1.printStackTrace();
710 // }
712 // }
714 // });
716 new MenuItem(men, SWT.SEPARATOR);
718 createImportProjectItem(men, repo, repo.getWorkDir().getPath());
720 new MenuItem(men, SWT.SEPARATOR);
722 MenuItem openPropsView = new MenuItem(men, SWT.PUSH);
723 openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu);
724 openPropsView.addSelectionListener(new SelectionAdapter() {
726 @Override
727 public void widgetSelected(SelectionEvent e) {
728 try {
729 PlatformUI.getWorkbench().getActiveWorkbenchWindow()
730 .getActivePage().showView(
731 IPageLayout.ID_PROP_SHEET);
732 } catch (PartInitException e1) {
733 // just ignore
739 new MenuItem(men, SWT.SEPARATOR);
741 createCopyPathItem(men, repo.getDirectory().getPath());
744 if (node.getType() == RepositoryTreeNodeType.REMOTES) {
746 MenuItem remoteConfig = new MenuItem(men, SWT.PUSH);
747 remoteConfig.setText(UIText.RepositoriesView_NewRemoteMenu);
748 remoteConfig.addSelectionListener(new SelectionAdapter() {
750 @Override
751 public void widgetSelected(SelectionEvent e) {
753 WizardDialog dlg = new WizardDialog(getSite().getShell(),
754 new NewRemoteWizard(node.getRepository()));
755 if (dlg.open() == Window.OK)
756 scheduleRefresh();
763 if (node.getType() == RepositoryTreeNodeType.REMOTE) {
765 final String configName = (String) node.getObject();
767 RemoteConfig rconfig;
768 try {
769 rconfig = new RemoteConfig(node.getRepository().getConfig(),
770 configName);
771 } catch (URISyntaxException e2) {
772 // TODO Exception handling
773 rconfig = null;
776 boolean fetchExists = rconfig != null
777 && !rconfig.getURIs().isEmpty();
778 boolean pushExists = rconfig != null
779 && !rconfig.getPushURIs().isEmpty();
781 if (!fetchExists) {
782 MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH);
783 configureUrlFetch
784 .setText(UIText.RepositoriesView_CreateFetch_menu);
786 configureUrlFetch.addSelectionListener(new SelectionAdapter() {
788 @Override
789 public void widgetSelected(SelectionEvent e) {
791 WizardDialog dlg = new WizardDialog(getSite()
792 .getShell(), new ConfigureRemoteWizard(node
793 .getRepository(), configName, false));
794 if (dlg.open() == Window.OK)
795 scheduleRefresh();
802 if (!pushExists) {
803 MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH);
805 configureUrlPush
806 .setText(UIText.RepositoriesView_CreatePush_menu);
808 configureUrlPush.addSelectionListener(new SelectionAdapter() {
810 @Override
811 public void widgetSelected(SelectionEvent e) {
813 WizardDialog dlg = new WizardDialog(getSite()
814 .getShell(), new ConfigureRemoteWizard(node
815 .getRepository(), configName, true));
816 if (dlg.open() == Window.OK)
817 scheduleRefresh();
824 if (!fetchExists || !pushExists)
825 // add a separator dynamically
826 new MenuItem(men, SWT.SEPARATOR);
828 MenuItem removeRemote = new MenuItem(men, SWT.PUSH);
829 removeRemote.setText(UIText.RepositoriesView_RemoveRemoteMenu);
830 removeRemote.addSelectionListener(new SelectionAdapter() {
832 @Override
833 public void widgetSelected(SelectionEvent e) {
835 boolean ok = MessageDialog
836 .openConfirm(
837 getSite().getShell(),
838 UIText.RepositoriesView_ConfirmDeleteRemoteHeader,
840 .bind(
841 UIText.RepositoriesView_ConfirmDeleteRemoteMessage,
842 configName));
843 if (ok) {
844 RepositoryConfig config = node.getRepository()
845 .getConfig();
846 config.unsetSection(REMOTE, configName);
847 try {
848 config.save();
849 scheduleRefresh();
850 } catch (IOException e1) {
851 Activator.handleError(
852 UIText.RepositoriesView_ErrorHeader, e1,
853 true);
861 new MenuItem(men, SWT.SEPARATOR);
863 MenuItem openPropsView = new MenuItem(men, SWT.PUSH);
864 openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu);
865 openPropsView.addSelectionListener(new SelectionAdapter() {
867 @Override
868 public void widgetSelected(SelectionEvent e) {
869 try {
870 PlatformUI.getWorkbench().getActiveWorkbenchWindow()
871 .getActivePage().showView(
872 IPageLayout.ID_PROP_SHEET);
873 } catch (PartInitException e1) {
874 // just ignore
881 if (node.getType() == RepositoryTreeNodeType.FETCH) {
883 final String configName = (String) node.getParent().getObject();
885 MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH);
886 configureUrlFetch
887 .setText(UIText.RepositoriesView_ConfigureFetchMenu);
889 configureUrlFetch.addSelectionListener(new SelectionAdapter() {
891 @Override
892 public void widgetSelected(SelectionEvent e) {
894 WizardDialog dlg = new WizardDialog(getSite().getShell(),
895 new ConfigureRemoteWizard(node.getRepository(),
896 configName, false));
897 if (dlg.open() == Window.OK)
898 scheduleRefresh();
904 MenuItem deleteFetch = new MenuItem(men, SWT.PUSH);
905 deleteFetch.setText(UIText.RepositoriesView_RemoveFetch_menu);
906 deleteFetch.addSelectionListener(new SelectionAdapter() {
908 @Override
909 public void widgetSelected(SelectionEvent e) {
910 RepositoryConfig config = node.getRepository().getConfig();
911 config.unset("remote", configName, "url"); //$NON-NLS-1$ //$NON-NLS-2$
912 config.unset("remote", configName, "fetch"); //$NON-NLS-1$//$NON-NLS-2$
913 try {
914 config.save();
915 scheduleRefresh();
916 } catch (IOException e1) {
917 MessageDialog.openError(getSite().getShell(),
918 UIText.RepositoriesView_ErrorHeader, e1
919 .getMessage());
927 if (node.getType() == RepositoryTreeNodeType.PUSH) {
929 final String configName = (String) node.getParent().getObject();
931 MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH);
933 configureUrlPush.setText(UIText.RepositoriesView_ConfigurePushMenu);
935 configureUrlPush.addSelectionListener(new SelectionAdapter() {
937 @Override
938 public void widgetSelected(SelectionEvent e) {
940 WizardDialog dlg = new WizardDialog(getSite().getShell(),
941 new ConfigureRemoteWizard(node.getRepository(),
942 configName, true));
943 if (dlg.open() == Window.OK)
944 scheduleRefresh();
949 MenuItem deleteFetch = new MenuItem(men, SWT.PUSH);
950 deleteFetch.setText(UIText.RepositoriesView_RemovePush_menu);
951 deleteFetch.addSelectionListener(new SelectionAdapter() {
953 @Override
954 public void widgetSelected(SelectionEvent e) {
955 RepositoryConfig config = node.getRepository().getConfig();
956 config.unset("remote", configName, "pushurl"); //$NON-NLS-1$ //$NON-NLS-2$
957 config.unset("remote", configName, "push"); //$NON-NLS-1$ //$NON-NLS-2$
958 try {
959 config.save();
960 scheduleRefresh();
961 } catch (IOException e1) {
962 MessageDialog.openError(getSite().getShell(),
963 UIText.RepositoriesView_ErrorHeader, e1
964 .getMessage());
971 if (node.getType() == RepositoryTreeNodeType.FILE) {
973 final File file = (File) node.getObject();
975 MenuItem openInTextEditor = new MenuItem(men, SWT.PUSH);
976 openInTextEditor
977 .setText(UIText.RepositoriesView_OpenInTextEditor_menu);
978 openInTextEditor.addSelectionListener(new SelectionAdapter() {
980 @Override
981 public void widgetSelected(SelectionEvent e) {
982 openFile(file);
987 new MenuItem(men, SWT.SEPARATOR);
988 createCopyPathItem(men, file.getPath());
991 if (node.getType() == RepositoryTreeNodeType.WORKINGDIR) {
992 String path = node.getRepository().getWorkDir().getAbsolutePath();
993 createImportProjectItem(men, node.getRepository(), path);
994 new MenuItem(men, SWT.SEPARATOR);
995 createCopyPathItem(men, path);
998 if (node.getType() == RepositoryTreeNodeType.FOLDER) {
999 String path = ((File) node.getObject()).getPath();
1000 createImportProjectItem(men, node.getRepository(), path);
1001 new MenuItem(men, SWT.SEPARATOR);
1002 createCopyPathItem(men, path);
1007 private void createCopyPathItem(Menu men, final String path) {
1009 MenuItem copyPath;
1010 copyPath = new MenuItem(men, SWT.PUSH);
1011 copyPath.setText(UIText.RepositoriesView_CopyPathToClipboardMenu);
1012 copyPath.addSelectionListener(new SelectionAdapter() {
1014 @Override
1015 public void widgetSelected(SelectionEvent e) {
1016 Clipboard clipboard = new Clipboard(null);
1017 TextTransfer textTransfer = TextTransfer.getInstance();
1018 Transfer[] transfers = new Transfer[] { textTransfer };
1019 Object[] data = new Object[] { path };
1020 clipboard.setContents(data, transfers);
1021 clipboard.dispose();
1028 private void createCreateBranchItem(Menu men, final RepositoryTreeNode node) {
1030 final boolean remoteMode;
1031 final Ref ref;
1032 if (node.getType() == RepositoryTreeNodeType.REF) {
1033 remoteMode = node.getParent().getType() == RepositoryTreeNodeType.REMOTEBRANCHES;
1034 ref = (Ref) node.getObject();
1035 } else if (node.getType() == RepositoryTreeNodeType.LOCALBRANCHES) {
1036 remoteMode = false;
1037 ref = null;
1038 } else if (node.getType() == RepositoryTreeNodeType.REMOTEBRANCHES) {
1039 remoteMode = true;
1040 ref = null;
1041 } else
1042 return;
1044 MenuItem createLocal = new MenuItem(men, SWT.PUSH);
1045 if (remoteMode)
1046 createLocal.setText(UIText.RepositoriesView_NewRemoteBranchMenu);
1047 else
1048 createLocal.setText(UIText.RepositoriesView_NewLocalBranchMenu);
1050 createLocal.addSelectionListener(new SelectionAdapter() {
1052 @Override
1053 public void widgetSelected(SelectionEvent e) {
1055 Wizard wiz = new Wizard() {
1057 @Override
1058 public void addPages() {
1059 addPage(new CreateBranchPage(node.getRepository(), ref,
1060 remoteMode));
1061 setWindowTitle(UIText.RepositoriesView_NewBranchTitle);
1064 @Override
1065 public boolean performFinish() {
1067 try {
1068 getContainer().run(false, true,
1069 new IRunnableWithProgress() {
1071 public void run(IProgressMonitor monitor)
1072 throws InvocationTargetException,
1073 InterruptedException {
1074 CreateBranchPage cp = (CreateBranchPage) getPages()[0];
1075 try {
1076 cp.createBranch(monitor);
1077 } catch (CoreException ce) {
1078 throw new InvocationTargetException(
1079 ce);
1080 } catch (IOException ioe) {
1081 throw new InvocationTargetException(
1082 ioe);
1087 } catch (InvocationTargetException ite) {
1088 Activator
1089 .handleError(
1090 UIText.RepositoriesView_BranchCreationFailureMessage,
1091 ite.getCause(), true);
1092 return false;
1093 } catch (InterruptedException ie) {
1094 // ignore here
1096 return true;
1099 if (new WizardDialog(getSite().getShell(), wiz).open() == Window.OK)
1100 scheduleRefresh();
1107 private void createDeleteBranchItem(Menu men, final RepositoryTreeNode node) {
1109 final Ref ref = (Ref) node.getObject();
1111 MenuItem deleteBranch = new MenuItem(men, SWT.PUSH);
1112 deleteBranch.setText(UIText.RepositoriesView_DeleteBranchMenu);
1114 try {
1115 if (node.getRepository().getFullBranch().equals(ref.getName())) {
1116 deleteBranch.setEnabled(false);
1118 } catch (IOException e2) {
1119 // ignore
1122 deleteBranch.addSelectionListener(new SelectionAdapter() {
1124 @Override
1125 public void widgetSelected(SelectionEvent e) {
1127 if (!MessageDialog
1128 .openConfirm(
1129 getSite().getShell(),
1130 UIText.RepositoriesView_ConfirmDeleteTitle,
1132 .bind(
1133 UIText.RepositoriesView_ConfirmBranchDeletionMessage,
1134 ref.getName())))
1135 return;
1137 try {
1138 new ProgressMonitorDialog(getSite().getShell()).run(false,
1139 false, new IRunnableWithProgress() {
1141 public void run(IProgressMonitor monitor)
1142 throws InvocationTargetException,
1143 InterruptedException {
1145 try {
1146 RefUpdate op = node.getRepository()
1147 .updateRef(ref.getName());
1148 op.setRefLogMessage("branch deleted", //$NON-NLS-1$
1149 false);
1150 // we set the force update in order
1151 // to avoid having this rejected
1152 // due to minor issues
1153 op.setForceUpdate(true);
1154 op.delete();
1155 scheduleRefresh();
1156 } catch (IOException ioe) {
1157 throw new InvocationTargetException(ioe);
1162 } catch (InvocationTargetException e1) {
1163 Activator
1164 .handleError(
1165 UIText.RepositoriesView_BranchDeletionFailureMessage,
1166 e1.getCause(), true);
1167 e1.printStackTrace();
1168 } catch (InterruptedException e1) {
1169 // ignore
1177 private void openFile(File file) {
1178 IFileStore store = EFS.getLocalFileSystem().getStore(
1179 new Path(file.getAbsolutePath()));
1180 try {
1181 // TODO do we need a read-only editor here?
1182 IDE.openEditor(getSite().getPage(),
1183 new FileStoreEditorInput(store),
1184 EditorsUI.DEFAULT_TEXT_EDITOR_ID);
1185 } catch (PartInitException e) {
1186 Activator.handleError(UIText.RepositoriesView_Error_WindowTitle, e,
1187 true);
1191 private void checkoutBranch(final RepositoryTreeNode node,
1192 final String refName) {
1193 // for the sake of UI responsiveness, let's start a job
1194 Job job = new Job(NLS.bind(UIText.RepositoriesView_CheckingOutMessage,
1195 refName)) {
1197 @Override
1198 protected IStatus run(IProgressMonitor monitor) {
1200 Repository repo = node.getRepository();
1202 final BranchOperation op = new BranchOperation(repo, refName);
1203 IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
1205 public void run(IProgressMonitor myMonitor)
1206 throws CoreException {
1207 op.execute(myMonitor);
1211 try {
1212 ResourcesPlugin.getWorkspace().run(wsr,
1213 ResourcesPlugin.getWorkspace().getRoot(),
1214 IWorkspace.AVOID_UPDATE, monitor);
1215 scheduleRefresh();
1216 } catch (CoreException e1) {
1217 return new Status(IStatus.ERROR, Activator.getPluginId(),
1218 e1.getMessage(), e1);
1221 return Status.OK_STATUS;
1225 job.setUser(true);
1226 job.schedule();
1229 private void createImportProjectItem(Menu men, final Repository repo,
1230 final String path) {
1232 MenuItem startWizard;
1233 startWizard = new MenuItem(men, SWT.PUSH);
1234 startWizard.setText(UIText.RepositoriesView_ImportProjectsMenu);
1235 startWizard.addSelectionListener(new SelectionAdapter() {
1237 @Override
1238 public void widgetSelected(SelectionEvent e) {
1239 WizardDialog dlg = new WizardDialog(getSite().getShell(),
1240 new GitCreateProjectViaWizardWizard(repo, path));
1241 if (dlg.open() == Window.OK)
1242 scheduleRefresh();
1248 // we could start the ImportWizard here,
1249 // unfortunately, this fails within a wizard
1250 // startWizard = new MenuItem(men, SWT.PUSH);
1251 // startWizard.setText("Start the Import wizard...");
1252 // startWizard.addSelectionListener(new SelectionAdapter() {
1254 // @Override
1255 // public void widgetSelected(SelectionEvent e) {
1257 // IHandlerService handlerService = (IHandlerService) getSite()
1258 // .getWorkbenchWindow().getWorkbench().getService(
1259 // IHandlerService.class);
1261 // try {
1262 // handlerService.executeCommand("org.eclipse.ui.file.import", //$NON-NLS-1$
1263 // null);
1264 // } catch (ExecutionException e1) {
1265 // Activator.handleError(e1.getMessage(), e1, true);
1266 // } catch (NotDefinedException e1) {
1267 // Activator.handleError(e1.getMessage(), e1, true);
1268 // } catch (NotEnabledException e1) {
1269 // Activator.handleError(e1.getMessage(), e1, true);
1270 // } catch (NotHandledException e1) {
1271 // Activator.handleError(e1.getMessage(), e1, true);
1272 // }
1273 // }
1275 // });
1278 private void addActionsToToolbar() {
1279 importAction = new Action(UIText.RepositoriesView_Import_Button) {
1281 @Override
1282 public void run() {
1283 GitCloneWizard wiz = new GitCloneWizard();
1284 wiz.init(null, null);
1285 new WizardDialog(getSite().getShell(), wiz).open();
1288 importAction.setToolTipText(UIText.RepositoriesView_Clone_Tooltip);
1290 importAction.setImageDescriptor(UIIcons.IMPORT);
1292 getViewSite().getActionBars().getToolBarManager().add(importAction);
1294 addAction = new Action(UIText.RepositoriesView_Add_Button) {
1296 @Override
1297 public void run() {
1298 RepositorySearchDialog sd = new RepositorySearchDialog(
1299 getSite().getShell(), getDirs());
1300 if (sd.open() == Window.OK) {
1301 Set<String> dirs = new HashSet<String>();
1302 dirs.addAll(getDirs());
1303 if (dirs.addAll(sd.getDirectories()))
1304 saveDirs(dirs);
1305 scheduleRefresh();
1310 addAction.setToolTipText(UIText.RepositoriesView_AddRepository_Tooltip);
1312 addAction.setImageDescriptor(UIIcons.NEW_REPOSITORY);
1314 getViewSite().getActionBars().getToolBarManager().add(addAction);
1316 linkWithSelectionAction = new Action(
1317 UIText.RepositoriesView_LinkWithSelection_action,
1318 IAction.AS_CHECK_BOX) {
1320 @Override
1321 public void run() {
1322 IEclipsePreferences prefs = getPrefs();
1323 prefs.putBoolean(PREFS_SYNCED, isChecked());
1324 try {
1325 prefs.flush();
1326 } catch (BackingStoreException e) {
1327 // ignore here
1329 if (isChecked()) {
1330 ISelectionService srv = (ISelectionService) getSite()
1331 .getService(ISelectionService.class);
1332 reactOnSelection(srv.getSelection());
1339 linkWithSelectionAction
1340 .setToolTipText(UIText.RepositoriesView_LinkWithSelection_action);
1342 linkWithSelectionAction.setImageDescriptor(UIIcons.ELCL16_SYNCED);
1344 linkWithSelectionAction.setChecked(getPrefs().getBoolean(PREFS_SYNCED,
1345 false));
1347 getViewSite().getActionBars().getToolBarManager().add(
1348 linkWithSelectionAction);
1350 refreshAction = new Action(UIText.RepositoriesView_Refresh_Button) {
1352 @Override
1353 public void run() {
1354 scheduleRefresh();
1358 refreshAction.setImageDescriptor(UIIcons.ELCL16_REFRESH);
1360 getViewSite().getActionBars().getToolBarManager().add(refreshAction);
1362 IAction collapseAllAction = new Action(
1363 UIText.RepositoriesView_CollapseAllMenu) {
1365 @Override
1366 public void run() {
1367 tv.collapseAll();
1372 collapseAllAction.setImageDescriptor(UIIcons.COLLAPSEALL);
1374 getViewSite().getActionBars().getToolBarManager()
1375 .add(collapseAllAction);
1379 * @return the preferences
1381 protected static IEclipsePreferences getPrefs() {
1382 return new InstanceScope().getNode(Activator.getPluginId());
1385 @Override
1386 public void dispose() {
1387 // make sure to cancel the refresh job
1388 if (this.scheduledJob != null) {
1389 this.scheduledJob.cancel();
1390 this.scheduledJob = null;
1392 super.dispose();
1396 * Schedules a refreh
1398 public void scheduleRefresh() {
1400 Job job = new Job("Refreshing Git Repositories view") { //$NON-NLS-1$
1402 @Override
1403 protected IStatus run(IProgressMonitor monitor) {
1405 final List<Repository> input;
1406 try {
1407 input = getRepositoriesFromDirs(monitor);
1408 } catch (InterruptedException e) {
1409 return new Status(IStatus.ERROR, Activator.getPluginId(), e
1410 .getMessage(), e);
1413 Display.getDefault().syncExec(new Runnable() {
1415 public void run() {
1416 // keep expansion state and selection so that we can
1417 // restore the tree
1418 // after update
1419 Object[] expanded = tv.getExpandedElements();
1420 IStructuredSelection sel = (IStructuredSelection) tv
1421 .getSelection();
1422 tv.setInput(input);
1423 tv.setExpandedElements(expanded);
1425 Object selected = sel.getFirstElement();
1426 if (selected != null)
1427 tv.reveal(selected);
1429 IViewPart part = PlatformUI.getWorkbench()
1430 .getActiveWorkbenchWindow().getActivePage()
1431 .findView(IPageLayout.ID_PROP_SHEET);
1432 if (part != null) {
1433 PropertySheet sheet = (PropertySheet) part;
1434 PropertySheetPage page = (PropertySheetPage) sheet
1435 .getCurrentPage();
1436 page.refresh();
1441 return new Status(IStatus.OK, Activator.getPluginId(), ""); //$NON-NLS-1$
1446 job.setSystem(true);
1448 IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getSite()
1449 .getService(IWorkbenchSiteProgressService.class);
1451 service.schedule(job);
1453 scheduledJob = job;
1457 private List<Repository> getRepositoriesFromDirs(IProgressMonitor monitor)
1458 throws InterruptedException {
1460 List<String> gitDirStrings = getDirs();
1461 List<Repository> input = new ArrayList<Repository>();
1462 for (String dirString : gitDirStrings) {
1463 if (monitor.isCanceled()) {
1464 throw new InterruptedException(
1465 UIText.RepositoriesView_ActionCanceled_Message);
1467 try {
1468 File dir = new File(dirString);
1469 if (dir.exists() && dir.isDirectory()) {
1470 input.add(new Repository(dir));
1472 } catch (IOException e) {
1473 IStatus error = new Status(IStatus.ERROR, Activator
1474 .getPluginId(), e.getMessage(), e);
1475 Activator.getDefault().getLog().log(error);
1478 return input;
1482 * Adds a directory to the list if it is not already there
1484 * @param file
1485 * @return see {@link Collection#add(Object)}
1487 public static boolean addDir(File file) {
1489 String dirString;
1490 try {
1491 dirString = file.getCanonicalPath();
1492 } catch (IOException e) {
1493 dirString = file.getAbsolutePath();
1496 List<String> dirStrings = getDirs();
1497 if (dirStrings.contains(dirString)) {
1498 return false;
1499 } else {
1500 Set<String> dirs = new HashSet<String>();
1501 dirs.addAll(dirStrings);
1502 dirs.add(dirString);
1503 saveDirs(dirs);
1504 return true;
1508 private static void saveDirs(Set<String> gitDirStrings) {
1509 StringBuilder sb = new StringBuilder();
1510 for (String gitDirString : gitDirStrings) {
1511 sb.append(gitDirString);
1512 sb.append(File.pathSeparatorChar);
1515 IEclipsePreferences prefs = getPrefs();
1516 prefs.put(PREFS_DIRECTORIES, sb.toString());
1517 try {
1518 prefs.flush();
1519 } catch (BackingStoreException e) {
1520 IStatus error = new Status(IStatus.ERROR, Activator.getPluginId(),
1521 e.getMessage(), e);
1522 Activator.getDefault().getLog().log(error);
1526 @Override
1527 public void setFocus() {
1528 tv.getTree().setFocus();
1531 @SuppressWarnings("boxing")
1532 private boolean confirmProjectDeletion(List<IProject> projectsToDelete) {
1533 boolean confirmed;
1534 confirmed = MessageDialog
1535 .openConfirm(
1536 getSite().getShell(),
1537 UIText.RepositoriesView_ConfirmProjectDeletion_WindowTitle,
1539 .bind(
1540 UIText.RepositoriesView_ConfirmProjectDeletion_Question,
1541 projectsToDelete.size()));
1542 return confirmed;
1545 public void addSelectionChangedListener(ISelectionChangedListener listener) {
1546 selectionListeners.add(listener);
1549 public ISelection getSelection() {
1550 return currentSelection;
1553 public void removeSelectionChangedListener(
1554 ISelectionChangedListener listener) {
1555 selectionListeners.remove(listener);
1559 public void setSelection(ISelection selection) {
1560 currentSelection = selection;
1561 for (ISelectionChangedListener listener : selectionListeners) {
1562 listener.selectionChanged(new SelectionChangedEvent(
1563 RepositoriesView.this, selection));
1568 * Opens the tree and marks the folder to which a project is pointing
1570 * @param resource
1571 * TODO exceptions?
1573 @SuppressWarnings("unchecked")
1574 public void showResource(final IResource resource) {
1575 IProject project = resource.getProject();
1576 RepositoryMapping mapping = RepositoryMapping.getMapping(project);
1577 if (mapping == null)
1578 return;
1580 if (addDir(mapping.getRepository().getDirectory())) {
1581 scheduleRefresh();
1584 boolean doSetSelection = false;
1586 if (this.scheduledJob != null) {
1587 int state = this.scheduledJob.getState();
1588 if (state == Job.WAITING || state == Job.RUNNING) {
1589 this.scheduledJob.addJobChangeListener(new JobChangeAdapter() {
1591 @Override
1592 public void done(IJobChangeEvent event) {
1593 showResource(resource);
1596 } else {
1597 doSetSelection = true;
1601 if (doSetSelection) {
1602 RepositoriesViewContentProvider cp = (RepositoriesViewContentProvider) tv
1603 .getContentProvider();
1604 RepositoryTreeNode currentNode = null;
1605 Object[] repos = cp.getElements(tv.getInput());
1606 for (Object repo : repos) {
1607 RepositoryTreeNode node = (RepositoryTreeNode) repo;
1608 // TODO equals implementation of Repository?
1609 if (mapping.getRepository().getDirectory().equals(
1610 ((Repository) node.getObject()).getDirectory())) {
1611 for (Object child : cp.getChildren(node)) {
1612 RepositoryTreeNode childNode = (RepositoryTreeNode) child;
1613 if (childNode.getType() == RepositoryTreeNodeType.WORKINGDIR) {
1614 currentNode = childNode;
1615 break;
1618 break;
1622 IPath relPath = new Path(mapping.getRepoRelativePath(resource));
1624 for (String segment : relPath.segments()) {
1625 for (Object child : cp.getChildren(currentNode)) {
1626 RepositoryTreeNode<File> childNode = (RepositoryTreeNode<File>) child;
1627 if (childNode.getObject().getName().equals(segment)) {
1628 currentNode = childNode;
1629 break;
1634 final RepositoryTreeNode selNode = currentNode;
1636 Display.getDefault().asyncExec(new Runnable() {
1638 public void run() {
1639 tv.setSelection(new StructuredSelection(selNode), true);
1647 public boolean show(ShowInContext context) {
1648 ISelection selection = context.getSelection();
1649 if (selection instanceof IStructuredSelection) {
1650 IStructuredSelection ss = (IStructuredSelection) selection;
1651 if (ss.size() == 1) {
1652 Object element = ss.getFirstElement();
1653 if (element instanceof IAdaptable) {
1654 IResource resource = (IResource) ((IAdaptable) element)
1655 .getAdapter(IResource.class);
1656 if (resource != null) {
1657 showResource(resource);
1658 return true;
1663 return false;