Git Import Wizard
[egit.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / repository / RepositoriesView.java
blobda2e7c1a848d5208242f1a5bcf8f1b41b49c01ef
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;
171 * TODO move to utility class
173 * @return the directories as configured for this view
175 public static List<String> getDirs() {
176 List<String> resultStrings = new ArrayList<String>();
177 String dirs = getPrefs().get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$
178 if (dirs != null && dirs.length() > 0) {
179 StringTokenizer tok = new StringTokenizer(dirs, File.pathSeparator);
180 while (tok.hasMoreTokens()) {
181 String dirName = tok.nextToken();
182 File testFile = new File(dirName);
183 if (testFile.exists()) {
184 resultStrings.add(dirName);
188 Collections.sort(resultStrings);
189 return resultStrings;
192 private static void removeDir(File file) {
194 String dir;
195 try {
196 dir = file.getCanonicalPath();
197 } catch (IOException e1) {
198 dir = file.getAbsolutePath();
201 IEclipsePreferences prefs = getPrefs();
203 TreeSet<String> resultStrings = new TreeSet<String>();
204 String dirs = prefs.get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$
205 if (dirs != null && dirs.length() > 0) {
206 StringTokenizer tok = new StringTokenizer(dirs, File.pathSeparator);
207 while (tok.hasMoreTokens()) {
208 String dirName = tok.nextToken();
209 File testFile = new File(dirName);
210 if (testFile.exists()) {
211 try {
212 resultStrings.add(testFile.getCanonicalPath());
213 } catch (IOException e) {
214 resultStrings.add(testFile.getAbsolutePath());
220 if (resultStrings.remove(dir)) {
221 StringBuilder sb = new StringBuilder();
222 for (String gitDirString : resultStrings) {
223 sb.append(gitDirString);
224 sb.append(File.pathSeparatorChar);
227 prefs.put(PREFS_DIRECTORIES, sb.toString());
228 try {
229 prefs.flush();
230 } catch (BackingStoreException e) {
231 IStatus error = new Status(IStatus.ERROR, Activator
232 .getPluginId(), e.getMessage(), e);
233 Activator.getDefault().getLog().log(error);
239 @Override
240 public Object getAdapter(Class adapter) {
241 // integrate with Properties view
242 if (adapter == IPropertySheetPage.class) {
243 PropertySheetPage page = new PropertySheetPage();
244 page
245 .setPropertySourceProvider(new RepositoryPropertySourceProvider(
246 page));
247 return page;
250 return super.getAdapter(adapter);
253 @Override
254 public void createPartControl(Composite parent) {
255 tv = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
256 tv.setContentProvider(new RepositoriesViewContentProvider());
257 // the label provider registers itself
258 new RepositoriesViewLabelProvider(tv);
260 getSite().setSelectionProvider(this);
262 tv.addSelectionChangedListener(new ISelectionChangedListener() {
264 public void selectionChanged(SelectionChangedEvent event) {
266 IStructuredSelection ssel = (IStructuredSelection) event
267 .getSelection();
268 if (ssel.size() == 1) {
269 setSelection(new StructuredSelection(ssel.getFirstElement()));
270 } else {
271 setSelection(new StructuredSelection());
276 tv.addOpenListener(new IOpenListener() {
277 public void open(OpenEvent event) {
278 IStructuredSelection selection = (IStructuredSelection) event
279 .getSelection();
280 if (selection.isEmpty()) {
281 // nothing selected, ignore
282 return;
285 Object element = selection.getFirstElement();
286 ITreeContentProvider contentProvider = (ITreeContentProvider) tv
287 .getContentProvider();
288 if (contentProvider.hasChildren(element)) {
289 // this element has children, expand/collapse it
290 tv.setExpandedState(element, !tv.getExpandedState(element));
291 } else {
292 Object[] selectionArray = selection.toArray();
293 for (Object selectedElement : selectionArray) {
294 RepositoryTreeNode node = (RepositoryTreeNode) selectedElement;
295 // if any of the selected elements are not files, ignore
296 // the open request
297 if (node.getType() != RepositoryTreeNodeType.FILE
298 && node.getType() != RepositoryTreeNodeType.REF) {
299 return;
303 // open the files the user has selected
304 for (Object selectedElement : selectionArray) {
305 RepositoryTreeNode node = (RepositoryTreeNode) selectedElement;
306 if (node.getType() == RepositoryTreeNodeType.FILE)
307 openFile((File) node.getObject());
308 else if (node.getType() == RepositoryTreeNodeType.REF) {
309 Ref ref = (Ref) node.getObject();
310 if (ref.getName().startsWith(Constants.R_HEADS)
311 || ref.getName().startsWith(
312 Constants.R_REMOTES))
313 checkoutBranch(node, ref.getName());
320 addContextMenu();
322 addActionsToToolbar();
324 scheduleRefresh();
326 ISelectionService srv = (ISelectionService) getSite().getService(
327 ISelectionService.class);
328 srv.addPostSelectionListener(new ISelectionListener() {
330 public void selectionChanged(IWorkbenchPart part,
331 ISelection selection) {
333 // if the "link with selection" toggle is off, we're done
334 if (linkWithSelectionAction == null
335 || !linkWithSelectionAction.isChecked())
336 return;
338 // this may happen if we switch between editors
339 if (part instanceof IEditorPart) {
340 IEditorInput input = ((IEditorPart) part).getEditorInput();
341 if (input instanceof IFileEditorInput)
342 reactOnSelection(new StructuredSelection(
343 ((IFileEditorInput) input).getFile()));
345 } else {
346 reactOnSelection(selection);
353 private void reactOnSelection(ISelection selection) {
354 if (selection instanceof StructuredSelection) {
355 StructuredSelection ssel = (StructuredSelection) selection;
356 if (ssel.size() != 1)
357 return;
358 if (ssel.getFirstElement() instanceof IResource) {
359 showResource((IResource) ssel.getFirstElement());
361 if (ssel.getFirstElement() instanceof IAdaptable) {
362 IResource adapted = (IResource) ((IAdaptable) ssel
363 .getFirstElement()).getAdapter(IResource.class);
364 if (adapted != null)
365 showResource(adapted);
370 private void addContextMenu() {
371 tv.getTree().addMenuDetectListener(new MenuDetectListener() {
373 public void menuDetected(MenuDetectEvent e) {
375 tv.getTree().setMenu(null);
376 Menu men = new Menu(tv.getTree());
378 TreeItem testItem = tv.getTree().getItem(
379 tv.getTree().toControl(new Point(e.x, e.y)));
380 if (testItem == null) {
381 addMenuItemsForPanel(men);
382 } else {
383 addMenuItemsForTreeSelection(men);
386 tv.getTree().setMenu(men);
391 private void addMenuItemsForPanel(Menu men) {
393 MenuItem importItem = new MenuItem(men, SWT.PUSH);
394 importItem.setText(UIText.RepositoriesView_ImportRepository_MenuItem);
395 importItem.addSelectionListener(new SelectionAdapter() {
397 @Override
398 public void widgetSelected(SelectionEvent e) {
399 importAction.run();
404 MenuItem addItem = new MenuItem(men, SWT.PUSH);
405 addItem.setText(UIText.RepositoriesView_AddRepository_MenuItem);
406 addItem.addSelectionListener(new SelectionAdapter() {
408 @Override
409 public void widgetSelected(SelectionEvent e) {
410 addAction.run();
415 MenuItem refreshItem = new MenuItem(men, SWT.PUSH);
416 refreshItem.setText(refreshAction.getText());
417 refreshItem.addSelectionListener(new SelectionAdapter() {
419 @Override
420 public void widgetSelected(SelectionEvent e) {
421 refreshAction.run();
428 @SuppressWarnings("unchecked")
429 private void addMenuItemsForTreeSelection(Menu men) {
431 final IStructuredSelection sel = (IStructuredSelection) tv
432 .getSelection();
434 boolean importableProjectsOnly = true;
436 for (Object node : sel.toArray()) {
437 RepositoryTreeNode tnode = (RepositoryTreeNode) node;
438 importableProjectsOnly = tnode.getType() == RepositoryTreeNodeType.PROJ;
439 if (!importableProjectsOnly)
440 break;
443 if (importableProjectsOnly) {
444 MenuItem sync = new MenuItem(men, SWT.PUSH);
445 sync.setText(UIText.RepositoriesView_ImportProject_MenuItem);
447 sync.addSelectionListener(new SelectionAdapter() {
449 @Override
450 public void widgetSelected(SelectionEvent e) {
452 IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
454 public void run(IProgressMonitor monitor)
455 throws CoreException {
457 for (Object selected : sel.toArray()) {
458 RepositoryTreeNode<File> projectNode = (RepositoryTreeNode<File>) selected;
459 File file = projectNode.getObject();
461 IProjectDescription pd = ResourcesPlugin
462 .getWorkspace().newProjectDescription(
463 file.getName());
464 IPath locationPath = new Path(file
465 .getAbsolutePath());
467 pd.setLocation(locationPath);
469 ResourcesPlugin.getWorkspace().getRoot()
470 .getProject(pd.getName()).create(pd,
471 monitor);
472 IProject project = ResourcesPlugin
473 .getWorkspace().getRoot().getProject(
474 pd.getName());
475 project.open(monitor);
477 File gitDir = projectNode.getRepository()
478 .getDirectory();
480 ConnectProviderOperation connectProviderOperation = new ConnectProviderOperation(
481 project, gitDir);
482 connectProviderOperation
483 .execute(new SubProgressMonitor(
484 monitor, 20));
491 try {
493 ResourcesPlugin.getWorkspace().run(wsr,
494 ResourcesPlugin.getWorkspace().getRoot(),
495 IWorkspace.AVOID_UPDATE,
496 new NullProgressMonitor());
498 scheduleRefresh();
499 } catch (CoreException e1) {
500 Activator.logError(e1.getMessage(), e1);
508 // from here on, we only deal with single selection
509 if (sel.size() > 1)
510 return;
512 final RepositoryTreeNode node = (RepositoryTreeNode) sel
513 .getFirstElement();
515 if (node.getType() == RepositoryTreeNodeType.REF) {
517 final Ref ref = (Ref) node.getObject();
519 // we don't check out symbolic references
520 if (!ref.isSymbolic()) {
522 MenuItem checkout = new MenuItem(men, SWT.PUSH);
523 checkout.setText(UIText.RepositoriesView_CheckOut_MenuItem);
525 try {
526 if (node.getRepository().getFullBranch().equals(
527 ref.getName())) {
528 // no checkout on current branch
529 checkout.setEnabled(false);
531 } catch (IOException e2) {
532 // ignore
535 checkout.addSelectionListener(new SelectionAdapter() {
537 @Override
538 public void widgetSelected(SelectionEvent e) {
539 checkoutBranch(node, ref.getLeaf().getName());
543 new MenuItem(men, SWT.SEPARATOR);
545 createCreateBranchItem(men, node);
546 createDeleteBranchItem(men, node);
551 if (node.getType() == RepositoryTreeNodeType.LOCALBRANCHES
552 || node.getType() == RepositoryTreeNodeType.REMOTEBRANCHES)
553 createCreateBranchItem(men, node);
555 // for Repository: import existing projects, remove, (delete), open
556 // properties
557 if (node.getType() == RepositoryTreeNodeType.REPO) {
559 final Repository repo = (Repository) node.getObject();
561 // TODO "import existing plug-in" menu item
563 MenuItem remove = new MenuItem(men, SWT.PUSH);
564 remove.setText(UIText.RepositoriesView_Remove_MenuItem);
565 remove.addSelectionListener(new SelectionAdapter() {
567 @Override
568 public void widgetSelected(SelectionEvent e) {
570 List<IProject> projectsToDelete = new ArrayList<IProject>();
571 File workDir = repo.getWorkDir();
572 final IPath wdPath = new Path(workDir.getAbsolutePath());
573 for (IProject prj : ResourcesPlugin.getWorkspace()
574 .getRoot().getProjects()) {
575 if (wdPath.isPrefixOf(prj.getLocation())) {
576 projectsToDelete.add(prj);
580 if (!projectsToDelete.isEmpty()) {
581 boolean confirmed;
582 confirmed = confirmProjectDeletion(projectsToDelete);
583 if (!confirmed) {
584 return;
588 IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
590 public void run(IProgressMonitor monitor)
591 throws CoreException {
593 for (IProject prj : ResourcesPlugin.getWorkspace()
594 .getRoot().getProjects()) {
595 if (wdPath.isPrefixOf(prj.getLocation())) {
596 prj.delete(false, false, monitor);
600 removeDir(repo.getDirectory());
601 scheduleRefresh();
605 try {
606 ResourcesPlugin.getWorkspace().run(wsr,
607 ResourcesPlugin.getWorkspace().getRoot(),
608 IWorkspace.AVOID_UPDATE,
609 new NullProgressMonitor());
610 } catch (CoreException e1) {
611 Activator.logError(e1.getMessage(), e1);
618 // TODO delete does not work because of file locks on .pack-files
619 // Shawn Pearce has added the following thoughts:
621 // Hmm. We probably can't active detect file locks on pack files on
622 // Windows, can we?
623 // It would be nice if we could support a delete, but only if the
624 // repository is
625 // reasonably believed to be not-in-use right now.
627 // Within EGit you might be able to check GitProjectData and its
628 // repositoryCache to
629 // see if the repository is open by this workspace. If it is, then
630 // we know we shouldn't
631 // try to delete it.
633 // Some coding might look like this:
635 // MenuItem deleteRepo = new MenuItem(men, SWT.PUSH);
636 // deleteRepo.setText("Delete");
637 // deleteRepo.addSelectionListener(new SelectionAdapter() {
639 // @Override
640 // public void widgetSelected(SelectionEvent e) {
642 // boolean confirmed = MessageDialog.openConfirm(getSite()
643 // .getShell(), "Confirm",
644 // "This will delete the repository, continue?");
646 // if (!confirmed)
647 // return;
649 // IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
651 // public void run(IProgressMonitor monitor)
652 // throws CoreException {
653 // File workDir = repos.get(0).getRepository()
654 // .getWorkDir();
656 // File gitDir = repos.get(0).getRepository()
657 // .getDirectory();
659 // IPath wdPath = new Path(workDir.getAbsolutePath());
660 // for (IProject prj : ResourcesPlugin.getWorkspace()
661 // .getRoot().getProjects()) {
662 // if (wdPath.isPrefixOf(prj.getLocation())) {
663 // prj.delete(false, false, monitor);
664 // }
665 // }
667 // repos.get(0).getRepository().close();
669 // boolean deleted = deleteRecursively(gitDir, monitor);
670 // if (!deleted) {
671 // MessageDialog.openError(getSite().getShell(),
672 // "Error",
673 // "Could not delete Git Repository");
674 // }
676 // deleted = deleteRecursively(workDir, monitor);
677 // if (!deleted) {
678 // MessageDialog
679 // .openError(getSite().getShell(),
680 // "Error",
681 // "Could not delete Git Working Directory");
682 // }
684 // scheduleRefresh();
685 // }
687 // private boolean deleteRecursively(File fileToDelete,
688 // IProgressMonitor monitor) {
689 // if (fileToDelete.isDirectory()) {
690 // for (File file : fileToDelete.listFiles()) {
691 // if (!deleteRecursively(file, monitor)) {
692 // return false;
693 // }
694 // }
695 // }
696 // monitor.setTaskName(fileToDelete.getAbsolutePath());
697 // boolean deleted = fileToDelete.delete();
698 // if (!deleted) {
699 // System.err.println("Could not delete "
700 // + fileToDelete.getAbsolutePath());
701 // }
702 // return deleted;
703 // }
704 // };
706 // try {
707 // ResourcesPlugin.getWorkspace().run(wsr,
708 // ResourcesPlugin.getWorkspace().getRoot(),
709 // IWorkspace.AVOID_UPDATE,
710 // new NullProgressMonitor());
711 // } catch (CoreException e1) {
712 // // TODO Exception handling
713 // e1.printStackTrace();
714 // }
716 // }
718 // });
720 new MenuItem(men, SWT.SEPARATOR);
722 createImportProjectItem(men, repo, repo.getWorkDir().getPath());
724 new MenuItem(men, SWT.SEPARATOR);
726 MenuItem openPropsView = new MenuItem(men, SWT.PUSH);
727 openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu);
728 openPropsView.addSelectionListener(new SelectionAdapter() {
730 @Override
731 public void widgetSelected(SelectionEvent e) {
732 try {
733 PlatformUI.getWorkbench().getActiveWorkbenchWindow()
734 .getActivePage().showView(
735 IPageLayout.ID_PROP_SHEET);
736 } catch (PartInitException e1) {
737 // just ignore
743 new MenuItem(men, SWT.SEPARATOR);
745 createCopyPathItem(men, repo.getDirectory().getPath());
748 if (node.getType() == RepositoryTreeNodeType.REMOTES) {
750 MenuItem remoteConfig = new MenuItem(men, SWT.PUSH);
751 remoteConfig.setText(UIText.RepositoriesView_NewRemoteMenu);
752 remoteConfig.addSelectionListener(new SelectionAdapter() {
754 @Override
755 public void widgetSelected(SelectionEvent e) {
757 WizardDialog dlg = new WizardDialog(getSite().getShell(),
758 new NewRemoteWizard(node.getRepository()));
759 if (dlg.open() == Window.OK)
760 scheduleRefresh();
767 if (node.getType() == RepositoryTreeNodeType.REMOTE) {
769 final String configName = (String) node.getObject();
771 RemoteConfig rconfig;
772 try {
773 rconfig = new RemoteConfig(node.getRepository().getConfig(),
774 configName);
775 } catch (URISyntaxException e2) {
776 // TODO Exception handling
777 rconfig = null;
780 boolean fetchExists = rconfig != null
781 && !rconfig.getURIs().isEmpty();
782 boolean pushExists = rconfig != null
783 && !rconfig.getPushURIs().isEmpty();
785 if (!fetchExists) {
786 MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH);
787 configureUrlFetch
788 .setText(UIText.RepositoriesView_CreateFetch_menu);
790 configureUrlFetch.addSelectionListener(new SelectionAdapter() {
792 @Override
793 public void widgetSelected(SelectionEvent e) {
795 WizardDialog dlg = new WizardDialog(getSite()
796 .getShell(), new ConfigureRemoteWizard(node
797 .getRepository(), configName, false));
798 if (dlg.open() == Window.OK)
799 scheduleRefresh();
806 if (!pushExists) {
807 MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH);
809 configureUrlPush
810 .setText(UIText.RepositoriesView_CreatePush_menu);
812 configureUrlPush.addSelectionListener(new SelectionAdapter() {
814 @Override
815 public void widgetSelected(SelectionEvent e) {
817 WizardDialog dlg = new WizardDialog(getSite()
818 .getShell(), new ConfigureRemoteWizard(node
819 .getRepository(), configName, true));
820 if (dlg.open() == Window.OK)
821 scheduleRefresh();
828 if (!fetchExists || !pushExists)
829 // add a separator dynamically
830 new MenuItem(men, SWT.SEPARATOR);
832 MenuItem removeRemote = new MenuItem(men, SWT.PUSH);
833 removeRemote.setText(UIText.RepositoriesView_RemoveRemoteMenu);
834 removeRemote.addSelectionListener(new SelectionAdapter() {
836 @Override
837 public void widgetSelected(SelectionEvent e) {
839 boolean ok = MessageDialog
840 .openConfirm(
841 getSite().getShell(),
842 UIText.RepositoriesView_ConfirmDeleteRemoteHeader,
844 .bind(
845 UIText.RepositoriesView_ConfirmDeleteRemoteMessage,
846 configName));
847 if (ok) {
848 RepositoryConfig config = node.getRepository()
849 .getConfig();
850 config.unsetSection(REMOTE, configName);
851 try {
852 config.save();
853 scheduleRefresh();
854 } catch (IOException e1) {
855 Activator.handleError(
856 UIText.RepositoriesView_ErrorHeader, e1,
857 true);
865 new MenuItem(men, SWT.SEPARATOR);
867 MenuItem openPropsView = new MenuItem(men, SWT.PUSH);
868 openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu);
869 openPropsView.addSelectionListener(new SelectionAdapter() {
871 @Override
872 public void widgetSelected(SelectionEvent e) {
873 try {
874 PlatformUI.getWorkbench().getActiveWorkbenchWindow()
875 .getActivePage().showView(
876 IPageLayout.ID_PROP_SHEET);
877 } catch (PartInitException e1) {
878 // just ignore
885 if (node.getType() == RepositoryTreeNodeType.FETCH) {
887 final String configName = (String) node.getParent().getObject();
889 MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH);
890 configureUrlFetch
891 .setText(UIText.RepositoriesView_ConfigureFetchMenu);
893 configureUrlFetch.addSelectionListener(new SelectionAdapter() {
895 @Override
896 public void widgetSelected(SelectionEvent e) {
898 WizardDialog dlg = new WizardDialog(getSite().getShell(),
899 new ConfigureRemoteWizard(node.getRepository(),
900 configName, false));
901 if (dlg.open() == Window.OK)
902 scheduleRefresh();
908 MenuItem deleteFetch = new MenuItem(men, SWT.PUSH);
909 deleteFetch.setText(UIText.RepositoriesView_RemoveFetch_menu);
910 deleteFetch.addSelectionListener(new SelectionAdapter() {
912 @Override
913 public void widgetSelected(SelectionEvent e) {
914 RepositoryConfig config = node.getRepository().getConfig();
915 config.unset("remote", configName, "url"); //$NON-NLS-1$ //$NON-NLS-2$
916 config.unset("remote", configName, "fetch"); //$NON-NLS-1$//$NON-NLS-2$
917 try {
918 config.save();
919 scheduleRefresh();
920 } catch (IOException e1) {
921 MessageDialog.openError(getSite().getShell(),
922 UIText.RepositoriesView_ErrorHeader, e1
923 .getMessage());
931 if (node.getType() == RepositoryTreeNodeType.PUSH) {
933 final String configName = (String) node.getParent().getObject();
935 MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH);
937 configureUrlPush.setText(UIText.RepositoriesView_ConfigurePushMenu);
939 configureUrlPush.addSelectionListener(new SelectionAdapter() {
941 @Override
942 public void widgetSelected(SelectionEvent e) {
944 WizardDialog dlg = new WizardDialog(getSite().getShell(),
945 new ConfigureRemoteWizard(node.getRepository(),
946 configName, true));
947 if (dlg.open() == Window.OK)
948 scheduleRefresh();
953 MenuItem deleteFetch = new MenuItem(men, SWT.PUSH);
954 deleteFetch.setText(UIText.RepositoriesView_RemovePush_menu);
955 deleteFetch.addSelectionListener(new SelectionAdapter() {
957 @Override
958 public void widgetSelected(SelectionEvent e) {
959 RepositoryConfig config = node.getRepository().getConfig();
960 config.unset("remote", configName, "pushurl"); //$NON-NLS-1$ //$NON-NLS-2$
961 config.unset("remote", configName, "push"); //$NON-NLS-1$ //$NON-NLS-2$
962 try {
963 config.save();
964 scheduleRefresh();
965 } catch (IOException e1) {
966 MessageDialog.openError(getSite().getShell(),
967 UIText.RepositoriesView_ErrorHeader, e1
968 .getMessage());
975 if (node.getType() == RepositoryTreeNodeType.FILE) {
977 final File file = (File) node.getObject();
979 MenuItem openInTextEditor = new MenuItem(men, SWT.PUSH);
980 openInTextEditor
981 .setText(UIText.RepositoriesView_OpenInTextEditor_menu);
982 openInTextEditor.addSelectionListener(new SelectionAdapter() {
984 @Override
985 public void widgetSelected(SelectionEvent e) {
986 openFile(file);
991 new MenuItem(men, SWT.SEPARATOR);
992 createCopyPathItem(men, file.getPath());
995 if (node.getType() == RepositoryTreeNodeType.WORKINGDIR) {
996 String path = node.getRepository().getWorkDir().getAbsolutePath();
997 createImportProjectItem(men, node.getRepository(), path);
998 new MenuItem(men, SWT.SEPARATOR);
999 createCopyPathItem(men, path);
1002 if (node.getType() == RepositoryTreeNodeType.FOLDER) {
1003 String path = ((File) node.getObject()).getPath();
1004 createImportProjectItem(men, node.getRepository(), path);
1005 new MenuItem(men, SWT.SEPARATOR);
1006 createCopyPathItem(men, path);
1011 private void createCopyPathItem(Menu men, final String path) {
1013 MenuItem copyPath;
1014 copyPath = new MenuItem(men, SWT.PUSH);
1015 copyPath.setText(UIText.RepositoriesView_CopyPathToClipboardMenu);
1016 copyPath.addSelectionListener(new SelectionAdapter() {
1018 @Override
1019 public void widgetSelected(SelectionEvent e) {
1020 Clipboard clipboard = new Clipboard(null);
1021 TextTransfer textTransfer = TextTransfer.getInstance();
1022 Transfer[] transfers = new Transfer[] { textTransfer };
1023 Object[] data = new Object[] { path };
1024 clipboard.setContents(data, transfers);
1025 clipboard.dispose();
1032 private void createCreateBranchItem(Menu men, final RepositoryTreeNode node) {
1034 final boolean remoteMode;
1035 final Ref ref;
1036 if (node.getType() == RepositoryTreeNodeType.REF) {
1037 remoteMode = node.getParent().getType() == RepositoryTreeNodeType.REMOTEBRANCHES;
1038 ref = (Ref) node.getObject();
1039 } else if (node.getType() == RepositoryTreeNodeType.LOCALBRANCHES) {
1040 remoteMode = false;
1041 ref = null;
1042 } else if (node.getType() == RepositoryTreeNodeType.REMOTEBRANCHES) {
1043 remoteMode = true;
1044 ref = null;
1045 } else
1046 return;
1048 MenuItem createLocal = new MenuItem(men, SWT.PUSH);
1049 if (remoteMode)
1050 createLocal.setText(UIText.RepositoriesView_NewRemoteBranchMenu);
1051 else
1052 createLocal.setText(UIText.RepositoriesView_NewLocalBranchMenu);
1054 createLocal.addSelectionListener(new SelectionAdapter() {
1056 @Override
1057 public void widgetSelected(SelectionEvent e) {
1059 Wizard wiz = new Wizard() {
1061 @Override
1062 public void addPages() {
1063 addPage(new CreateBranchPage(node.getRepository(), ref,
1064 remoteMode));
1065 setWindowTitle(UIText.RepositoriesView_NewBranchTitle);
1068 @Override
1069 public boolean performFinish() {
1071 try {
1072 getContainer().run(false, true,
1073 new IRunnableWithProgress() {
1075 public void run(IProgressMonitor monitor)
1076 throws InvocationTargetException,
1077 InterruptedException {
1078 CreateBranchPage cp = (CreateBranchPage) getPages()[0];
1079 try {
1080 cp.createBranch(monitor);
1081 } catch (CoreException ce) {
1082 throw new InvocationTargetException(
1083 ce);
1084 } catch (IOException ioe) {
1085 throw new InvocationTargetException(
1086 ioe);
1091 } catch (InvocationTargetException ite) {
1092 Activator
1093 .handleError(
1094 UIText.RepositoriesView_BranchCreationFailureMessage,
1095 ite.getCause(), true);
1096 return false;
1097 } catch (InterruptedException ie) {
1098 // ignore here
1100 return true;
1103 if (new WizardDialog(getSite().getShell(), wiz).open() == Window.OK)
1104 scheduleRefresh();
1111 private void createDeleteBranchItem(Menu men, final RepositoryTreeNode node) {
1113 final Ref ref = (Ref) node.getObject();
1115 MenuItem deleteBranch = new MenuItem(men, SWT.PUSH);
1116 deleteBranch.setText(UIText.RepositoriesView_DeleteBranchMenu);
1118 try {
1119 if (node.getRepository().getFullBranch().equals(ref.getName())) {
1120 deleteBranch.setEnabled(false);
1122 } catch (IOException e2) {
1123 // ignore
1126 deleteBranch.addSelectionListener(new SelectionAdapter() {
1128 @Override
1129 public void widgetSelected(SelectionEvent e) {
1131 if (!MessageDialog
1132 .openConfirm(
1133 getSite().getShell(),
1134 UIText.RepositoriesView_ConfirmDeleteTitle,
1136 .bind(
1137 UIText.RepositoriesView_ConfirmBranchDeletionMessage,
1138 ref.getName())))
1139 return;
1141 try {
1142 new ProgressMonitorDialog(getSite().getShell()).run(false,
1143 false, new IRunnableWithProgress() {
1145 public void run(IProgressMonitor monitor)
1146 throws InvocationTargetException,
1147 InterruptedException {
1149 try {
1150 RefUpdate op = node.getRepository()
1151 .updateRef(ref.getName());
1152 op.setRefLogMessage("branch deleted", //$NON-NLS-1$
1153 false);
1154 // we set the force update in order
1155 // to avoid having this rejected
1156 // due to minor issues
1157 op.setForceUpdate(true);
1158 op.delete();
1159 scheduleRefresh();
1160 } catch (IOException ioe) {
1161 throw new InvocationTargetException(ioe);
1166 } catch (InvocationTargetException e1) {
1167 Activator
1168 .handleError(
1169 UIText.RepositoriesView_BranchDeletionFailureMessage,
1170 e1.getCause(), true);
1171 e1.printStackTrace();
1172 } catch (InterruptedException e1) {
1173 // ignore
1181 private void openFile(File file) {
1182 IFileStore store = EFS.getLocalFileSystem().getStore(
1183 new Path(file.getAbsolutePath()));
1184 try {
1185 // TODO do we need a read-only editor here?
1186 IDE.openEditor(getSite().getPage(),
1187 new FileStoreEditorInput(store),
1188 EditorsUI.DEFAULT_TEXT_EDITOR_ID);
1189 } catch (PartInitException e) {
1190 Activator.handleError(UIText.RepositoriesView_Error_WindowTitle, e,
1191 true);
1195 private void checkoutBranch(final RepositoryTreeNode node,
1196 final String refName) {
1197 // for the sake of UI responsiveness, let's start a job
1198 Job job = new Job(NLS.bind(UIText.RepositoriesView_CheckingOutMessage,
1199 refName)) {
1201 @Override
1202 protected IStatus run(IProgressMonitor monitor) {
1204 Repository repo = node.getRepository();
1206 final BranchOperation op = new BranchOperation(repo, refName);
1207 IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
1209 public void run(IProgressMonitor myMonitor)
1210 throws CoreException {
1211 op.execute(myMonitor);
1215 try {
1216 ResourcesPlugin.getWorkspace().run(wsr,
1217 ResourcesPlugin.getWorkspace().getRoot(),
1218 IWorkspace.AVOID_UPDATE, monitor);
1219 scheduleRefresh();
1220 } catch (CoreException e1) {
1221 return new Status(IStatus.ERROR, Activator.getPluginId(),
1222 e1.getMessage(), e1);
1225 return Status.OK_STATUS;
1229 job.setUser(true);
1230 job.schedule();
1233 private void createImportProjectItem(Menu men, final Repository repo,
1234 final String path) {
1236 MenuItem startWizard;
1237 startWizard = new MenuItem(men, SWT.PUSH);
1238 startWizard.setText(UIText.RepositoriesView_ImportProjectsMenu);
1239 startWizard.addSelectionListener(new SelectionAdapter() {
1241 @Override
1242 public void widgetSelected(SelectionEvent e) {
1243 WizardDialog dlg = new WizardDialog(getSite().getShell(),
1244 new GitCreateProjectViaWizardWizard(repo, path));
1245 if (dlg.open() == Window.OK)
1246 scheduleRefresh();
1252 // we could start the ImportWizard here,
1253 // unfortunately, this fails within a wizard
1254 // startWizard = new MenuItem(men, SWT.PUSH);
1255 // startWizard.setText("Start the Import wizard...");
1256 // startWizard.addSelectionListener(new SelectionAdapter() {
1258 // @Override
1259 // public void widgetSelected(SelectionEvent e) {
1261 // IHandlerService handlerService = (IHandlerService) getSite()
1262 // .getWorkbenchWindow().getWorkbench().getService(
1263 // IHandlerService.class);
1265 // try {
1266 // handlerService.executeCommand("org.eclipse.ui.file.import", //$NON-NLS-1$
1267 // null);
1268 // } catch (ExecutionException e1) {
1269 // Activator.handleError(e1.getMessage(), e1, true);
1270 // } catch (NotDefinedException e1) {
1271 // Activator.handleError(e1.getMessage(), e1, true);
1272 // } catch (NotEnabledException e1) {
1273 // Activator.handleError(e1.getMessage(), e1, true);
1274 // } catch (NotHandledException e1) {
1275 // Activator.handleError(e1.getMessage(), e1, true);
1276 // }
1277 // }
1279 // });
1282 private void addActionsToToolbar() {
1283 importAction = new Action(UIText.RepositoriesView_Import_Button) {
1285 @Override
1286 public void run() {
1287 WizardDialog dlg = new WizardDialog(getSite().getShell(),
1288 new GitCloneWizard());
1289 if (dlg.open() == Window.OK)
1290 scheduleRefresh();
1293 importAction.setToolTipText(UIText.RepositoriesView_Clone_Tooltip);
1295 importAction.setImageDescriptor(UIIcons.IMPORT);
1297 getViewSite().getActionBars().getToolBarManager().add(importAction);
1299 addAction = new Action(UIText.RepositoriesView_Add_Button) {
1301 @Override
1302 public void run() {
1303 RepositorySearchDialog sd = new RepositorySearchDialog(
1304 getSite().getShell(), getDirs());
1305 if (sd.open() == Window.OK) {
1306 Set<String> dirs = new HashSet<String>();
1307 dirs.addAll(getDirs());
1308 if (dirs.addAll(sd.getDirectories()))
1309 saveDirs(dirs);
1310 scheduleRefresh();
1315 addAction.setToolTipText(UIText.RepositoriesView_AddRepository_Tooltip);
1317 addAction.setImageDescriptor(UIIcons.NEW_REPOSITORY);
1319 getViewSite().getActionBars().getToolBarManager().add(addAction);
1321 linkWithSelectionAction = new Action(
1322 UIText.RepositoriesView_LinkWithSelection_action,
1323 IAction.AS_CHECK_BOX) {
1325 @Override
1326 public void run() {
1327 IEclipsePreferences prefs = getPrefs();
1328 prefs.putBoolean(PREFS_SYNCED, isChecked());
1329 try {
1330 prefs.flush();
1331 } catch (BackingStoreException e) {
1332 // ignore here
1334 if (isChecked()) {
1335 ISelectionService srv = (ISelectionService) getSite()
1336 .getService(ISelectionService.class);
1337 reactOnSelection(srv.getSelection());
1344 linkWithSelectionAction
1345 .setToolTipText(UIText.RepositoriesView_LinkWithSelection_action);
1347 linkWithSelectionAction.setImageDescriptor(UIIcons.ELCL16_SYNCED);
1349 linkWithSelectionAction.setChecked(getPrefs().getBoolean(PREFS_SYNCED,
1350 false));
1352 getViewSite().getActionBars().getToolBarManager().add(
1353 linkWithSelectionAction);
1355 refreshAction = new Action(UIText.RepositoriesView_Refresh_Button) {
1357 @Override
1358 public void run() {
1359 scheduleRefresh();
1363 refreshAction.setImageDescriptor(UIIcons.ELCL16_REFRESH);
1365 getViewSite().getActionBars().getToolBarManager().add(refreshAction);
1367 IAction collapseAllAction = new Action(
1368 UIText.RepositoriesView_CollapseAllMenu) {
1370 @Override
1371 public void run() {
1372 tv.collapseAll();
1377 collapseAllAction.setImageDescriptor(UIIcons.COLLAPSEALL);
1379 getViewSite().getActionBars().getToolBarManager()
1380 .add(collapseAllAction);
1384 * @return the preferences
1386 protected static IEclipsePreferences getPrefs() {
1387 return new InstanceScope().getNode(Activator.getPluginId());
1390 @Override
1391 public void dispose() {
1392 // make sure to cancel the refresh job
1393 if (this.scheduledJob != null) {
1394 this.scheduledJob.cancel();
1395 this.scheduledJob = null;
1397 super.dispose();
1401 * Schedules a refreh
1403 public void scheduleRefresh() {
1405 Job job = new Job("Refreshing Git Repositories view") { //$NON-NLS-1$
1407 @Override
1408 protected IStatus run(IProgressMonitor monitor) {
1410 final List<RepositoryTreeNode<Repository>> input;
1411 try {
1412 input = getRepositoriesFromDirs(monitor);
1413 } catch (InterruptedException e) {
1414 return new Status(IStatus.ERROR, Activator.getPluginId(), e
1415 .getMessage(), e);
1418 boolean needsNewInput = tv.getInput() == null;
1419 List oldInput = (List) tv.getInput();
1420 if (!needsNewInput)
1421 needsNewInput = oldInput.size() != input.size();
1423 if (!needsNewInput) {
1424 for (int i = 0; i < input.size(); i++) {
1425 needsNewInput = !input.get(i).equals(oldInput.get(i));
1426 if (needsNewInput)
1427 break;
1431 final boolean updateInput = needsNewInput;
1433 Display.getDefault().syncExec(new Runnable() {
1435 public void run() {
1436 // keep expansion state and selection so that we can
1437 // restore the tree
1438 // after update
1439 Object[] expanded = tv.getExpandedElements();
1440 IStructuredSelection sel = (IStructuredSelection) tv
1441 .getSelection();
1442 if (updateInput)
1443 tv.setInput(input);
1444 else
1445 tv.refresh();
1446 tv.setExpandedElements(expanded);
1448 Object selected = sel.getFirstElement();
1449 if (selected != null)
1450 tv.reveal(selected);
1452 IViewPart part = PlatformUI.getWorkbench()
1453 .getActiveWorkbenchWindow().getActivePage()
1454 .findView(IPageLayout.ID_PROP_SHEET);
1455 if (part != null) {
1456 PropertySheet sheet = (PropertySheet) part;
1457 PropertySheetPage page = (PropertySheetPage) sheet
1458 .getCurrentPage();
1459 page.refresh();
1464 return new Status(IStatus.OK, Activator.getPluginId(), ""); //$NON-NLS-1$
1469 job.setSystem(true);
1471 IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getSite()
1472 .getService(IWorkbenchSiteProgressService.class);
1474 service.schedule(job);
1476 scheduledJob = job;
1481 * Adds a directory to the list if it is not already there
1483 * @param file
1484 * @return see {@link Collection#add(Object)}
1486 public static boolean addDir(File file) {
1488 String dirString;
1489 try {
1490 dirString = file.getCanonicalPath();
1491 } catch (IOException e) {
1492 dirString = file.getAbsolutePath();
1495 List<String> dirStrings = getDirs();
1496 if (dirStrings.contains(dirString)) {
1497 return false;
1498 } else {
1499 Set<String> dirs = new HashSet<String>();
1500 dirs.addAll(dirStrings);
1501 dirs.add(dirString);
1502 saveDirs(dirs);
1503 return true;
1508 * Converts the directories as configured for this view into a list of
1509 * {@link Repository} objects suitable for the tree content provider
1510 * <p>
1511 * TODO move to some utility class
1513 * @param monitor
1514 * @return a list of nodes
1515 * @throws InterruptedException
1517 public static List<RepositoryTreeNode<Repository>> getRepositoriesFromDirs(
1518 IProgressMonitor monitor) throws InterruptedException {
1520 List<String> gitDirStrings = getDirs();
1521 List<RepositoryTreeNode<Repository>> input = new ArrayList<RepositoryTreeNode<Repository>>();
1523 for (String dirString : gitDirStrings) {
1524 if (monitor != null && monitor.isCanceled()) {
1525 throw new InterruptedException(
1526 UIText.RepositoriesView_ActionCanceled_Message);
1528 try {
1529 File dir = new File(dirString);
1530 if (dir.exists() && dir.isDirectory()) {
1531 Repository repo = new Repository(dir);
1532 RepositoryTreeNode<Repository> node = new RepositoryTreeNode<Repository>(
1533 null, RepositoryTreeNodeType.REPO, repo, repo);
1534 input.add(node);
1536 } catch (IOException e) {
1537 IStatus error = new Status(IStatus.ERROR, Activator
1538 .getPluginId(), e.getMessage(), e);
1539 Activator.getDefault().getLog().log(error);
1542 Collections.sort(input);
1543 return input;
1546 private static void saveDirs(Set<String> gitDirStrings) {
1547 StringBuilder sb = new StringBuilder();
1548 for (String gitDirString : gitDirStrings) {
1549 sb.append(gitDirString);
1550 sb.append(File.pathSeparatorChar);
1553 IEclipsePreferences prefs = getPrefs();
1554 prefs.put(PREFS_DIRECTORIES, sb.toString());
1555 try {
1556 prefs.flush();
1557 } catch (BackingStoreException e) {
1558 IStatus error = new Status(IStatus.ERROR, Activator.getPluginId(),
1559 e.getMessage(), e);
1560 Activator.getDefault().getLog().log(error);
1564 @Override
1565 public void setFocus() {
1566 tv.getTree().setFocus();
1569 @SuppressWarnings("boxing")
1570 private boolean confirmProjectDeletion(List<IProject> projectsToDelete) {
1571 boolean confirmed;
1572 confirmed = MessageDialog
1573 .openConfirm(
1574 getSite().getShell(),
1575 UIText.RepositoriesView_ConfirmProjectDeletion_WindowTitle,
1577 .bind(
1578 UIText.RepositoriesView_ConfirmProjectDeletion_Question,
1579 projectsToDelete.size()));
1580 return confirmed;
1583 public void addSelectionChangedListener(ISelectionChangedListener listener) {
1584 selectionListeners.add(listener);
1587 public ISelection getSelection() {
1588 return currentSelection;
1591 public void removeSelectionChangedListener(
1592 ISelectionChangedListener listener) {
1593 selectionListeners.remove(listener);
1597 public void setSelection(ISelection selection) {
1598 currentSelection = selection;
1599 for (ISelectionChangedListener listener : selectionListeners) {
1600 listener.selectionChanged(new SelectionChangedEvent(
1601 RepositoriesView.this, selection));
1606 * Opens the tree and marks the folder to which a project is pointing
1608 * @param resource
1609 * TODO exceptions?
1611 @SuppressWarnings("unchecked")
1612 public void showResource(final IResource resource) {
1613 IProject project = resource.getProject();
1614 RepositoryMapping mapping = RepositoryMapping.getMapping(project);
1615 if (mapping == null)
1616 return;
1618 if (addDir(mapping.getRepository().getDirectory())) {
1619 scheduleRefresh();
1622 boolean doSetSelection = false;
1624 if (this.scheduledJob != null) {
1625 int state = this.scheduledJob.getState();
1626 if (state == Job.WAITING || state == Job.RUNNING) {
1627 this.scheduledJob.addJobChangeListener(new JobChangeAdapter() {
1629 @Override
1630 public void done(IJobChangeEvent event) {
1631 showResource(resource);
1634 } else {
1635 doSetSelection = true;
1639 if (doSetSelection) {
1640 RepositoriesViewContentProvider cp = (RepositoriesViewContentProvider) tv
1641 .getContentProvider();
1642 RepositoryTreeNode currentNode = null;
1643 Object[] repos = cp.getElements(tv.getInput());
1644 for (Object repo : repos) {
1645 RepositoryTreeNode node = (RepositoryTreeNode) repo;
1646 // TODO equals implementation of Repository?
1647 if (mapping.getRepository().getDirectory().equals(
1648 ((Repository) node.getObject()).getDirectory())) {
1649 for (Object child : cp.getChildren(node)) {
1650 RepositoryTreeNode childNode = (RepositoryTreeNode) child;
1651 if (childNode.getType() == RepositoryTreeNodeType.WORKINGDIR) {
1652 currentNode = childNode;
1653 break;
1656 break;
1660 IPath relPath = new Path(mapping.getRepoRelativePath(resource));
1662 for (String segment : relPath.segments()) {
1663 for (Object child : cp.getChildren(currentNode)) {
1664 RepositoryTreeNode<File> childNode = (RepositoryTreeNode<File>) child;
1665 if (childNode.getObject().getName().equals(segment)) {
1666 currentNode = childNode;
1667 break;
1672 final RepositoryTreeNode selNode = currentNode;
1674 Display.getDefault().asyncExec(new Runnable() {
1676 public void run() {
1677 tv.setSelection(new StructuredSelection(selNode), true);
1685 public boolean show(ShowInContext context) {
1686 ISelection selection = context.getSelection();
1687 if (selection instanceof IStructuredSelection) {
1688 IStructuredSelection ss = (IStructuredSelection) selection;
1689 if (ss.size() == 1) {
1690 Object element = ss.getFirstElement();
1691 if (element instanceof IAdaptable) {
1692 IResource resource = (IResource) ((IAdaptable) element)
1693 .getAdapter(IResource.class);
1694 if (resource != null) {
1695 showResource(resource);
1696 return true;
1701 return false;