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
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org
.eclipse
.egit
.ui
.internal
.repository
;
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
;
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.
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.
126 * Implements {@link ISelectionProvider} in order to integrate with the
130 * <li>Clarification whether to show projects, perhaps configurable switch</li>
133 public class RepositoriesView
extends ViewPart
implements ISelectionProvider
,
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
) {
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()) {
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());
230 } catch (BackingStoreException e
) {
231 IStatus error
= new Status(IStatus
.ERROR
, Activator
232 .getPluginId(), e
.getMessage(), e
);
233 Activator
.getDefault().getLog().log(error
);
240 public Object
getAdapter(Class adapter
) {
241 // integrate with Properties view
242 if (adapter
== IPropertySheetPage
.class) {
243 PropertySheetPage page
= new PropertySheetPage();
245 .setPropertySourceProvider(new RepositoryPropertySourceProvider(
250 return super.getAdapter(adapter
);
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
268 if (ssel
.size() == 1) {
269 setSelection(new StructuredSelection(ssel
.getFirstElement()));
271 setSelection(new StructuredSelection());
276 tv
.addOpenListener(new IOpenListener() {
277 public void open(OpenEvent event
) {
278 IStructuredSelection selection
= (IStructuredSelection
) event
280 if (selection
.isEmpty()) {
281 // nothing selected, ignore
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
));
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
297 if (node
.getType() != RepositoryTreeNodeType
.FILE
298 && node
.getType() != RepositoryTreeNodeType
.REF
) {
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());
322 addActionsToToolbar();
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())
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()));
346 reactOnSelection(selection
);
353 private void reactOnSelection(ISelection selection
) {
354 if (selection
instanceof StructuredSelection
) {
355 StructuredSelection ssel
= (StructuredSelection
) selection
;
356 if (ssel
.size() != 1)
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);
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
);
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() {
398 public void widgetSelected(SelectionEvent e
) {
404 MenuItem addItem
= new MenuItem(men
, SWT
.PUSH
);
405 addItem
.setText(UIText
.RepositoriesView_AddRepository_MenuItem
);
406 addItem
.addSelectionListener(new SelectionAdapter() {
409 public void widgetSelected(SelectionEvent e
) {
415 MenuItem refreshItem
= new MenuItem(men
, SWT
.PUSH
);
416 refreshItem
.setText(refreshAction
.getText());
417 refreshItem
.addSelectionListener(new SelectionAdapter() {
420 public void widgetSelected(SelectionEvent e
) {
428 @SuppressWarnings("unchecked")
429 private void addMenuItemsForTreeSelection(Menu men
) {
431 final IStructuredSelection sel
= (IStructuredSelection
) tv
434 boolean importableProjectsOnly
= true;
436 for (Object node
: sel
.toArray()) {
437 RepositoryTreeNode tnode
= (RepositoryTreeNode
) node
;
438 importableProjectsOnly
= tnode
.getType() == RepositoryTreeNodeType
.PROJ
;
439 if (!importableProjectsOnly
)
443 if (importableProjectsOnly
) {
444 MenuItem sync
= new MenuItem(men
, SWT
.PUSH
);
445 sync
.setText(UIText
.RepositoriesView_ImportProject_MenuItem
);
447 sync
.addSelectionListener(new SelectionAdapter() {
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(
464 IPath locationPath
= new Path(file
467 pd
.setLocation(locationPath
);
469 ResourcesPlugin
.getWorkspace().getRoot()
470 .getProject(pd
.getName()).create(pd
,
472 IProject project
= ResourcesPlugin
473 .getWorkspace().getRoot().getProject(
475 project
.open(monitor
);
477 File gitDir
= projectNode
.getRepository()
480 ConnectProviderOperation connectProviderOperation
= new ConnectProviderOperation(
482 connectProviderOperation
483 .execute(new SubProgressMonitor(
493 ResourcesPlugin
.getWorkspace().run(wsr
,
494 ResourcesPlugin
.getWorkspace().getRoot(),
495 IWorkspace
.AVOID_UPDATE
,
496 new NullProgressMonitor());
499 } catch (CoreException e1
) {
500 Activator
.logError(e1
.getMessage(), e1
);
508 // from here on, we only deal with single selection
512 final RepositoryTreeNode node
= (RepositoryTreeNode
) sel
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
);
526 if (node
.getRepository().getFullBranch().equals(
528 // no checkout on current branch
529 checkout
.setEnabled(false);
531 } catch (IOException e2
) {
535 checkout
.addSelectionListener(new SelectionAdapter() {
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
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() {
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()) {
582 confirmed
= confirmProjectDeletion(projectsToDelete
);
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());
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
623 // It would be nice if we could support a delete, but only if the
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
633 // Some coding might look like this:
635 // MenuItem deleteRepo = new MenuItem(men, SWT.PUSH);
636 // deleteRepo.setText("Delete");
637 // deleteRepo.addSelectionListener(new SelectionAdapter() {
640 // public void widgetSelected(SelectionEvent e) {
642 // boolean confirmed = MessageDialog.openConfirm(getSite()
643 // .getShell(), "Confirm",
644 // "This will delete the repository, continue?");
649 // IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
651 // public void run(IProgressMonitor monitor)
652 // throws CoreException {
653 // File workDir = repos.get(0).getRepository()
656 // File gitDir = repos.get(0).getRepository()
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);
667 // repos.get(0).getRepository().close();
669 // boolean deleted = deleteRecursively(gitDir, monitor);
671 // MessageDialog.openError(getSite().getShell(),
673 // "Could not delete Git Repository");
676 // deleted = deleteRecursively(workDir, monitor);
679 // .openError(getSite().getShell(),
681 // "Could not delete Git Working Directory");
684 // scheduleRefresh();
687 // private boolean deleteRecursively(File fileToDelete,
688 // IProgressMonitor monitor) {
689 // if (fileToDelete.isDirectory()) {
690 // for (File file : fileToDelete.listFiles()) {
691 // if (!deleteRecursively(file, monitor)) {
696 // monitor.setTaskName(fileToDelete.getAbsolutePath());
697 // boolean deleted = fileToDelete.delete();
699 // System.err.println("Could not delete "
700 // + fileToDelete.getAbsolutePath());
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();
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() {
731 public void widgetSelected(SelectionEvent e
) {
733 PlatformUI
.getWorkbench().getActiveWorkbenchWindow()
734 .getActivePage().showView(
735 IPageLayout
.ID_PROP_SHEET
);
736 } catch (PartInitException e1
) {
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() {
755 public void widgetSelected(SelectionEvent e
) {
757 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
758 new NewRemoteWizard(node
.getRepository()));
759 if (dlg
.open() == Window
.OK
)
767 if (node
.getType() == RepositoryTreeNodeType
.REMOTE
) {
769 final String configName
= (String
) node
.getObject();
771 RemoteConfig rconfig
;
773 rconfig
= new RemoteConfig(node
.getRepository().getConfig(),
775 } catch (URISyntaxException e2
) {
776 // TODO Exception handling
780 boolean fetchExists
= rconfig
!= null
781 && !rconfig
.getURIs().isEmpty();
782 boolean pushExists
= rconfig
!= null
783 && !rconfig
.getPushURIs().isEmpty();
786 MenuItem configureUrlFetch
= new MenuItem(men
, SWT
.PUSH
);
788 .setText(UIText
.RepositoriesView_CreateFetch_menu
);
790 configureUrlFetch
.addSelectionListener(new SelectionAdapter() {
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
)
807 MenuItem configureUrlPush
= new MenuItem(men
, SWT
.PUSH
);
810 .setText(UIText
.RepositoriesView_CreatePush_menu
);
812 configureUrlPush
.addSelectionListener(new SelectionAdapter() {
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
)
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() {
837 public void widgetSelected(SelectionEvent e
) {
839 boolean ok
= MessageDialog
841 getSite().getShell(),
842 UIText
.RepositoriesView_ConfirmDeleteRemoteHeader
,
845 UIText
.RepositoriesView_ConfirmDeleteRemoteMessage
,
848 RepositoryConfig config
= node
.getRepository()
850 config
.unsetSection(REMOTE
, configName
);
854 } catch (IOException e1
) {
855 Activator
.handleError(
856 UIText
.RepositoriesView_ErrorHeader
, e1
,
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() {
872 public void widgetSelected(SelectionEvent e
) {
874 PlatformUI
.getWorkbench().getActiveWorkbenchWindow()
875 .getActivePage().showView(
876 IPageLayout
.ID_PROP_SHEET
);
877 } catch (PartInitException e1
) {
885 if (node
.getType() == RepositoryTreeNodeType
.FETCH
) {
887 final String configName
= (String
) node
.getParent().getObject();
889 MenuItem configureUrlFetch
= new MenuItem(men
, SWT
.PUSH
);
891 .setText(UIText
.RepositoriesView_ConfigureFetchMenu
);
893 configureUrlFetch
.addSelectionListener(new SelectionAdapter() {
896 public void widgetSelected(SelectionEvent e
) {
898 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
899 new ConfigureRemoteWizard(node
.getRepository(),
901 if (dlg
.open() == Window
.OK
)
908 MenuItem deleteFetch
= new MenuItem(men
, SWT
.PUSH
);
909 deleteFetch
.setText(UIText
.RepositoriesView_RemoveFetch_menu
);
910 deleteFetch
.addSelectionListener(new SelectionAdapter() {
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$
920 } catch (IOException e1
) {
921 MessageDialog
.openError(getSite().getShell(),
922 UIText
.RepositoriesView_ErrorHeader
, e1
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() {
942 public void widgetSelected(SelectionEvent e
) {
944 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
945 new ConfigureRemoteWizard(node
.getRepository(),
947 if (dlg
.open() == Window
.OK
)
953 MenuItem deleteFetch
= new MenuItem(men
, SWT
.PUSH
);
954 deleteFetch
.setText(UIText
.RepositoriesView_RemovePush_menu
);
955 deleteFetch
.addSelectionListener(new SelectionAdapter() {
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$
965 } catch (IOException e1
) {
966 MessageDialog
.openError(getSite().getShell(),
967 UIText
.RepositoriesView_ErrorHeader
, e1
975 if (node
.getType() == RepositoryTreeNodeType
.FILE
) {
977 final File file
= (File
) node
.getObject();
979 MenuItem openInTextEditor
= new MenuItem(men
, SWT
.PUSH
);
981 .setText(UIText
.RepositoriesView_OpenInTextEditor_menu
);
982 openInTextEditor
.addSelectionListener(new SelectionAdapter() {
985 public void widgetSelected(SelectionEvent e
) {
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
) {
1014 copyPath
= new MenuItem(men
, SWT
.PUSH
);
1015 copyPath
.setText(UIText
.RepositoriesView_CopyPathToClipboardMenu
);
1016 copyPath
.addSelectionListener(new SelectionAdapter() {
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
;
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
) {
1042 } else if (node
.getType() == RepositoryTreeNodeType
.REMOTEBRANCHES
) {
1048 MenuItem createLocal
= new MenuItem(men
, SWT
.PUSH
);
1050 createLocal
.setText(UIText
.RepositoriesView_NewRemoteBranchMenu
);
1052 createLocal
.setText(UIText
.RepositoriesView_NewLocalBranchMenu
);
1054 createLocal
.addSelectionListener(new SelectionAdapter() {
1057 public void widgetSelected(SelectionEvent e
) {
1059 Wizard wiz
= new Wizard() {
1062 public void addPages() {
1063 addPage(new CreateBranchPage(node
.getRepository(), ref
,
1065 setWindowTitle(UIText
.RepositoriesView_NewBranchTitle
);
1069 public boolean performFinish() {
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];
1080 cp
.createBranch(monitor
);
1081 } catch (CoreException ce
) {
1082 throw new InvocationTargetException(
1084 } catch (IOException ioe
) {
1085 throw new InvocationTargetException(
1091 } catch (InvocationTargetException ite
) {
1094 UIText
.RepositoriesView_BranchCreationFailureMessage
,
1095 ite
.getCause(), true);
1097 } catch (InterruptedException ie
) {
1103 if (new WizardDialog(getSite().getShell(), wiz
).open() == Window
.OK
)
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
);
1119 if (node
.getRepository().getFullBranch().equals(ref
.getName())) {
1120 deleteBranch
.setEnabled(false);
1122 } catch (IOException e2
) {
1126 deleteBranch
.addSelectionListener(new SelectionAdapter() {
1129 public void widgetSelected(SelectionEvent e
) {
1133 getSite().getShell(),
1134 UIText
.RepositoriesView_ConfirmDeleteTitle
,
1137 UIText
.RepositoriesView_ConfirmBranchDeletionMessage
,
1142 new ProgressMonitorDialog(getSite().getShell()).run(false,
1143 false, new IRunnableWithProgress() {
1145 public void run(IProgressMonitor monitor
)
1146 throws InvocationTargetException
,
1147 InterruptedException
{
1150 RefUpdate op
= node
.getRepository()
1151 .updateRef(ref
.getName());
1152 op
.setRefLogMessage("branch deleted", //$NON-NLS-1$
1154 // we set the force update in order
1155 // to avoid having this rejected
1156 // due to minor issues
1157 op
.setForceUpdate(true);
1160 } catch (IOException ioe
) {
1161 throw new InvocationTargetException(ioe
);
1166 } catch (InvocationTargetException e1
) {
1169 UIText
.RepositoriesView_BranchDeletionFailureMessage
,
1170 e1
.getCause(), true);
1171 e1
.printStackTrace();
1172 } catch (InterruptedException e1
) {
1181 private void openFile(File file
) {
1182 IFileStore store
= EFS
.getLocalFileSystem().getStore(
1183 new Path(file
.getAbsolutePath()));
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
,
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
,
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
);
1216 ResourcesPlugin
.getWorkspace().run(wsr
,
1217 ResourcesPlugin
.getWorkspace().getRoot(),
1218 IWorkspace
.AVOID_UPDATE
, monitor
);
1220 } catch (CoreException e1
) {
1221 return new Status(IStatus
.ERROR
, Activator
.getPluginId(),
1222 e1
.getMessage(), e1
);
1225 return Status
.OK_STATUS
;
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() {
1242 public void widgetSelected(SelectionEvent e
) {
1243 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
1244 new GitCreateProjectViaWizardWizard(repo
, path
));
1245 if (dlg
.open() == Window
.OK
)
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() {
1259 // public void widgetSelected(SelectionEvent e) {
1261 // IHandlerService handlerService = (IHandlerService) getSite()
1262 // .getWorkbenchWindow().getWorkbench().getService(
1263 // IHandlerService.class);
1266 // handlerService.executeCommand("org.eclipse.ui.file.import", //$NON-NLS-1$
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);
1282 private void addActionsToToolbar() {
1283 importAction
= new Action(UIText
.RepositoriesView_Import_Button
) {
1287 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
1288 new GitCloneWizard());
1289 if (dlg
.open() == Window
.OK
)
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
) {
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()))
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
) {
1327 IEclipsePreferences prefs
= getPrefs();
1328 prefs
.putBoolean(PREFS_SYNCED
, isChecked());
1331 } catch (BackingStoreException e
) {
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
,
1352 getViewSite().getActionBars().getToolBarManager().add(
1353 linkWithSelectionAction
);
1355 refreshAction
= new Action(UIText
.RepositoriesView_Refresh_Button
) {
1363 refreshAction
.setImageDescriptor(UIIcons
.ELCL16_REFRESH
);
1365 getViewSite().getActionBars().getToolBarManager().add(refreshAction
);
1367 IAction collapseAllAction
= new Action(
1368 UIText
.RepositoriesView_CollapseAllMenu
) {
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());
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;
1401 * Schedules a refreh
1403 public void scheduleRefresh() {
1405 Job job
= new Job("Refreshing Git Repositories view") { //$NON-NLS-1$
1408 protected IStatus
run(IProgressMonitor monitor
) {
1410 final List
<RepositoryTreeNode
<Repository
>> input
;
1412 input
= getRepositoriesFromDirs(monitor
);
1413 } catch (InterruptedException e
) {
1414 return new Status(IStatus
.ERROR
, Activator
.getPluginId(), e
1418 boolean needsNewInput
= tv
.getInput() == null;
1419 List oldInput
= (List
) tv
.getInput();
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
));
1431 final boolean updateInput
= needsNewInput
;
1433 Display
.getDefault().syncExec(new Runnable() {
1436 // keep expansion state and selection so that we can
1439 Object
[] expanded
= tv
.getExpandedElements();
1440 IStructuredSelection sel
= (IStructuredSelection
) tv
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
);
1456 PropertySheet sheet
= (PropertySheet
) part
;
1457 PropertySheetPage page
= (PropertySheetPage
) sheet
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
);
1481 * Adds a directory to the list if it is not already there
1484 * @return see {@link Collection#add(Object)}
1486 public static boolean addDir(File file
) {
1490 dirString
= file
.getCanonicalPath();
1491 } catch (IOException e
) {
1492 dirString
= file
.getAbsolutePath();
1495 List
<String
> dirStrings
= getDirs();
1496 if (dirStrings
.contains(dirString
)) {
1499 Set
<String
> dirs
= new HashSet
<String
>();
1500 dirs
.addAll(dirStrings
);
1501 dirs
.add(dirString
);
1508 * Converts the directories as configured for this view into a list of
1509 * {@link Repository} objects suitable for the tree content provider
1511 * TODO move to some utility class
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
);
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
);
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
);
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());
1557 } catch (BackingStoreException e
) {
1558 IStatus error
= new Status(IStatus
.ERROR
, Activator
.getPluginId(),
1560 Activator
.getDefault().getLog().log(error
);
1565 public void setFocus() {
1566 tv
.getTree().setFocus();
1569 @SuppressWarnings("boxing")
1570 private boolean confirmProjectDeletion(List
<IProject
> projectsToDelete
) {
1572 confirmed
= MessageDialog
1574 getSite().getShell(),
1575 UIText
.RepositoriesView_ConfirmProjectDeletion_WindowTitle
,
1578 UIText
.RepositoriesView_ConfirmProjectDeletion_Question
,
1579 projectsToDelete
.size()));
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
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)
1618 if (addDir(mapping
.getRepository().getDirectory())) {
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() {
1630 public void done(IJobChangeEvent event
) {
1631 showResource(resource
);
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
;
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
;
1672 final RepositoryTreeNode selNode
= currentNode
;
1674 Display
.getDefault().asyncExec(new Runnable() {
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
);