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
.RepositoryCache
;
80 import org
.eclipse
.jgit
.lib
.RepositoryConfig
;
81 import org
.eclipse
.jgit
.transport
.RemoteConfig
;
82 import org
.eclipse
.osgi
.util
.NLS
;
83 import org
.eclipse
.swt
.SWT
;
84 import org
.eclipse
.swt
.dnd
.Clipboard
;
85 import org
.eclipse
.swt
.dnd
.TextTransfer
;
86 import org
.eclipse
.swt
.dnd
.Transfer
;
87 import org
.eclipse
.swt
.events
.MenuDetectEvent
;
88 import org
.eclipse
.swt
.events
.MenuDetectListener
;
89 import org
.eclipse
.swt
.events
.SelectionAdapter
;
90 import org
.eclipse
.swt
.events
.SelectionEvent
;
91 import org
.eclipse
.swt
.graphics
.Point
;
92 import org
.eclipse
.swt
.widgets
.Composite
;
93 import org
.eclipse
.swt
.widgets
.Display
;
94 import org
.eclipse
.swt
.widgets
.Menu
;
95 import org
.eclipse
.swt
.widgets
.MenuItem
;
96 import org
.eclipse
.swt
.widgets
.TreeItem
;
97 import org
.eclipse
.ui
.IEditorInput
;
98 import org
.eclipse
.ui
.IEditorPart
;
99 import org
.eclipse
.ui
.IFileEditorInput
;
100 import org
.eclipse
.ui
.IPageLayout
;
101 import org
.eclipse
.ui
.ISelectionListener
;
102 import org
.eclipse
.ui
.ISelectionService
;
103 import org
.eclipse
.ui
.IViewPart
;
104 import org
.eclipse
.ui
.IWorkbenchPart
;
105 import org
.eclipse
.ui
.PartInitException
;
106 import org
.eclipse
.ui
.PlatformUI
;
107 import org
.eclipse
.ui
.actions
.ActionFactory
;
108 import org
.eclipse
.ui
.editors
.text
.EditorsUI
;
109 import org
.eclipse
.ui
.ide
.FileStoreEditorInput
;
110 import org
.eclipse
.ui
.ide
.IDE
;
111 import org
.eclipse
.ui
.part
.IShowInTarget
;
112 import org
.eclipse
.ui
.part
.ShowInContext
;
113 import org
.eclipse
.ui
.part
.ViewPart
;
114 import org
.eclipse
.ui
.progress
.IWorkbenchSiteProgressService
;
115 import org
.eclipse
.ui
.views
.properties
.IPropertySheetPage
;
116 import org
.eclipse
.ui
.views
.properties
.PropertySheet
;
117 import org
.eclipse
.ui
.views
.properties
.PropertySheetPage
;
118 import org
.osgi
.service
.prefs
.BackingStoreException
;
122 * The Git Repositories view.
124 * This keeps track of a bunch of local directory names each of which represent
125 * a Git Repository. This list is stored in some Preferences object and used to
126 * build the tree in the view.
128 * Implements {@link ISelectionProvider} in order to integrate with the
132 * <li>Clarification whether to show projects, perhaps configurable switch</li>
135 public class RepositoriesView
extends ViewPart
implements ISelectionProvider
,
139 public static final String VIEW_ID
= "org.eclipse.egit.ui.RepositoriesView"; //$NON-NLS-1$
141 // TODO central constants? RemoteConfig ones are private
142 static final String REMOTE
= "remote"; //$NON-NLS-1$
144 static final String URL
= "url"; //$NON-NLS-1$
146 static final String PUSHURL
= "pushurl"; //$NON-NLS-1$
148 static final String FETCH
= "fetch"; //$NON-NLS-1$
150 static final String PUSH
= "push"; //$NON-NLS-1$
152 private static final String PREFS_DIRECTORIES
= "GitRepositoriesView.GitDirectories"; //$NON-NLS-1$
154 private static final String PREFS_SYNCED
= "GitRepositoriesView.SyncWithSelection"; //$NON-NLS-1$
156 private final List
<ISelectionChangedListener
> selectionListeners
= new ArrayList
<ISelectionChangedListener
>();
158 private ISelection currentSelection
= new StructuredSelection();
160 private Job scheduledJob
;
162 private TreeViewer tv
;
164 private IAction importAction
;
166 private IAction addAction
;
168 private IAction refreshAction
;
170 private IAction linkWithSelectionAction
;
172 private IAction copyAction
;
174 private IAction pasteAction
;
177 * TODO move to utility class
179 * @return the directories as configured for this view
181 public static List
<String
> getDirs() {
182 List
<String
> resultStrings
= new ArrayList
<String
>();
183 String dirs
= getPrefs().get(PREFS_DIRECTORIES
, ""); //$NON-NLS-1$
184 if (dirs
!= null && dirs
.length() > 0) {
185 StringTokenizer tok
= new StringTokenizer(dirs
, File
.pathSeparator
);
186 while (tok
.hasMoreTokens()) {
187 String dirName
= tok
.nextToken();
188 File testFile
= new File(dirName
);
189 if (testFile
.exists()) {
190 resultStrings
.add(dirName
);
194 Collections
.sort(resultStrings
);
195 return resultStrings
;
198 private static void removeDir(File file
) {
202 dir
= file
.getCanonicalPath();
203 } catch (IOException e1
) {
204 dir
= file
.getAbsolutePath();
207 IEclipsePreferences prefs
= getPrefs();
209 TreeSet
<String
> resultStrings
= new TreeSet
<String
>();
210 String dirs
= prefs
.get(PREFS_DIRECTORIES
, ""); //$NON-NLS-1$
211 if (dirs
!= null && dirs
.length() > 0) {
212 StringTokenizer tok
= new StringTokenizer(dirs
, File
.pathSeparator
);
213 while (tok
.hasMoreTokens()) {
214 String dirName
= tok
.nextToken();
215 File testFile
= new File(dirName
);
216 if (testFile
.exists()) {
218 resultStrings
.add(testFile
.getCanonicalPath());
219 } catch (IOException e
) {
220 resultStrings
.add(testFile
.getAbsolutePath());
226 if (resultStrings
.remove(dir
)) {
227 StringBuilder sb
= new StringBuilder();
228 for (String gitDirString
: resultStrings
) {
229 sb
.append(gitDirString
);
230 sb
.append(File
.pathSeparatorChar
);
233 prefs
.put(PREFS_DIRECTORIES
, sb
.toString());
236 } catch (BackingStoreException e
) {
237 IStatus error
= new Status(IStatus
.ERROR
, Activator
238 .getPluginId(), e
.getMessage(), e
);
239 Activator
.getDefault().getLog().log(error
);
246 public Object
getAdapter(Class adapter
) {
247 // integrate with Properties view
248 if (adapter
== IPropertySheetPage
.class) {
249 PropertySheetPage page
= new PropertySheetPage();
251 .setPropertySourceProvider(new RepositoryPropertySourceProvider(
256 return super.getAdapter(adapter
);
260 public void createPartControl(Composite parent
) {
261 tv
= new TreeViewer(parent
, SWT
.MULTI
| SWT
.H_SCROLL
| SWT
.V_SCROLL
);
262 tv
.setContentProvider(new RepositoriesViewContentProvider());
263 // the label provider registers itself
264 new RepositoriesViewLabelProvider(tv
);
266 getSite().setSelectionProvider(this);
268 tv
.addSelectionChangedListener(new ISelectionChangedListener() {
270 public void selectionChanged(SelectionChangedEvent event
) {
272 copyAction
.setEnabled(false);
274 IStructuredSelection ssel
= (IStructuredSelection
) event
276 if (ssel
.size() == 1) {
277 RepositoryTreeNode node
= (RepositoryTreeNode
) ssel
279 // allow copy on repository, file, or folder (copying the
281 if (node
.getType() == RepositoryTreeNodeType
.REPO
282 || node
.getType() == RepositoryTreeNodeType
.WORKINGDIR
283 || node
.getType() == RepositoryTreeNodeType
.FOLDER
284 || node
.getType() == RepositoryTreeNodeType
.FILE
) {
285 copyAction
.setEnabled(true);
287 setSelection(new StructuredSelection(ssel
.getFirstElement()));
289 setSelection(new StructuredSelection());
294 tv
.addOpenListener(new IOpenListener() {
295 public void open(OpenEvent event
) {
296 IStructuredSelection selection
= (IStructuredSelection
) event
298 if (selection
.isEmpty()) {
299 // nothing selected, ignore
303 Object element
= selection
.getFirstElement();
304 ITreeContentProvider contentProvider
= (ITreeContentProvider
) tv
305 .getContentProvider();
306 if (contentProvider
.hasChildren(element
)) {
307 // this element has children, expand/collapse it
308 tv
.setExpandedState(element
, !tv
.getExpandedState(element
));
310 Object
[] selectionArray
= selection
.toArray();
311 for (Object selectedElement
: selectionArray
) {
312 RepositoryTreeNode node
= (RepositoryTreeNode
) selectedElement
;
313 // if any of the selected elements are not files, ignore
315 if (node
.getType() != RepositoryTreeNodeType
.FILE
316 && node
.getType() != RepositoryTreeNodeType
.REF
) {
321 // open the files the user has selected
322 for (Object selectedElement
: selectionArray
) {
323 RepositoryTreeNode node
= (RepositoryTreeNode
) selectedElement
;
324 if (node
.getType() == RepositoryTreeNodeType
.FILE
)
325 openFile((File
) node
.getObject());
326 else if (node
.getType() == RepositoryTreeNodeType
.REF
) {
327 Ref ref
= (Ref
) node
.getObject();
328 if (ref
.getName().startsWith(Constants
.R_HEADS
)
329 || ref
.getName().startsWith(
330 Constants
.R_REMOTES
))
331 checkoutBranch(node
, ref
.getName());
340 addActionsToToolbar();
344 ISelectionService srv
= (ISelectionService
) getSite().getService(
345 ISelectionService
.class);
346 srv
.addPostSelectionListener(new ISelectionListener() {
348 public void selectionChanged(IWorkbenchPart part
,
349 ISelection selection
) {
351 // if the "link with selection" toggle is off, we're done
352 if (linkWithSelectionAction
== null
353 || !linkWithSelectionAction
.isChecked())
356 // this may happen if we switch between editors
357 if (part
instanceof IEditorPart
) {
358 IEditorInput input
= ((IEditorPart
) part
).getEditorInput();
359 if (input
instanceof IFileEditorInput
)
360 reactOnSelection(new StructuredSelection(
361 ((IFileEditorInput
) input
).getFile()));
364 reactOnSelection(selection
);
371 private void reactOnSelection(ISelection selection
) {
372 if (selection
instanceof StructuredSelection
) {
373 StructuredSelection ssel
= (StructuredSelection
) selection
;
374 if (ssel
.size() != 1)
376 if (ssel
.getFirstElement() instanceof IResource
) {
377 showResource((IResource
) ssel
.getFirstElement());
379 if (ssel
.getFirstElement() instanceof IAdaptable
) {
380 IResource adapted
= (IResource
) ((IAdaptable
) ssel
381 .getFirstElement()).getAdapter(IResource
.class);
383 showResource(adapted
);
388 private void addContextMenu() {
389 tv
.getTree().addMenuDetectListener(new MenuDetectListener() {
391 public void menuDetected(MenuDetectEvent e
) {
393 tv
.getTree().setMenu(null);
394 Menu men
= new Menu(tv
.getTree());
396 TreeItem testItem
= tv
.getTree().getItem(
397 tv
.getTree().toControl(new Point(e
.x
, e
.y
)));
398 if (testItem
== null) {
399 addMenuItemsForPanel(men
);
401 addMenuItemsForTreeSelection(men
);
404 tv
.getTree().setMenu(men
);
409 private void addMenuItemsForPanel(Menu men
) {
411 MenuItem importItem
= new MenuItem(men
, SWT
.PUSH
);
412 importItem
.setText(UIText
.RepositoriesView_ImportRepository_MenuItem
);
413 importItem
.addSelectionListener(new SelectionAdapter() {
416 public void widgetSelected(SelectionEvent e
) {
422 MenuItem addItem
= new MenuItem(men
, SWT
.PUSH
);
423 addItem
.setText(UIText
.RepositoriesView_AddRepository_MenuItem
);
424 addItem
.addSelectionListener(new SelectionAdapter() {
427 public void widgetSelected(SelectionEvent e
) {
433 MenuItem pasteItem
= new MenuItem(men
, SWT
.PUSH
);
434 pasteItem
.setText(UIText
.RepositoriesView_PasteMenu
);
435 pasteItem
.addSelectionListener(new SelectionAdapter() {
438 public void widgetSelected(SelectionEvent e
) {
444 MenuItem refreshItem
= new MenuItem(men
, SWT
.PUSH
);
445 refreshItem
.setText(refreshAction
.getText());
446 refreshItem
.addSelectionListener(new SelectionAdapter() {
449 public void widgetSelected(SelectionEvent e
) {
457 @SuppressWarnings("unchecked")
458 private void addMenuItemsForTreeSelection(Menu men
) {
460 final IStructuredSelection sel
= (IStructuredSelection
) tv
463 boolean importableProjectsOnly
= true;
465 for (Object node
: sel
.toArray()) {
466 RepositoryTreeNode tnode
= (RepositoryTreeNode
) node
;
467 importableProjectsOnly
= tnode
.getType() == RepositoryTreeNodeType
.PROJ
;
468 if (!importableProjectsOnly
)
472 if (importableProjectsOnly
) {
473 MenuItem sync
= new MenuItem(men
, SWT
.PUSH
);
474 sync
.setText(UIText
.RepositoriesView_ImportProject_MenuItem
);
476 sync
.addSelectionListener(new SelectionAdapter() {
479 public void widgetSelected(SelectionEvent e
) {
481 IWorkspaceRunnable wsr
= new IWorkspaceRunnable() {
483 public void run(IProgressMonitor monitor
)
484 throws CoreException
{
486 for (Object selected
: sel
.toArray()) {
487 RepositoryTreeNode
<File
> projectNode
= (RepositoryTreeNode
<File
>) selected
;
488 File file
= projectNode
.getObject();
490 IProjectDescription pd
= ResourcesPlugin
491 .getWorkspace().newProjectDescription(
493 IPath locationPath
= new Path(file
496 pd
.setLocation(locationPath
);
498 ResourcesPlugin
.getWorkspace().getRoot()
499 .getProject(pd
.getName()).create(pd
,
501 IProject project
= ResourcesPlugin
502 .getWorkspace().getRoot().getProject(
504 project
.open(monitor
);
506 File gitDir
= projectNode
.getRepository()
509 ConnectProviderOperation connectProviderOperation
= new ConnectProviderOperation(
511 connectProviderOperation
512 .execute(new SubProgressMonitor(
522 ResourcesPlugin
.getWorkspace().run(wsr
,
523 ResourcesPlugin
.getWorkspace().getRoot(),
524 IWorkspace
.AVOID_UPDATE
,
525 new NullProgressMonitor());
528 } catch (CoreException e1
) {
529 Activator
.logError(e1
.getMessage(), e1
);
537 // from here on, we only deal with single selection
541 final RepositoryTreeNode node
= (RepositoryTreeNode
) sel
544 if (node
.getType() == RepositoryTreeNodeType
.REF
) {
546 final Ref ref
= (Ref
) node
.getObject();
548 // we don't check out symbolic references
549 if (!ref
.isSymbolic()) {
551 MenuItem checkout
= new MenuItem(men
, SWT
.PUSH
);
552 checkout
.setText(UIText
.RepositoriesView_CheckOut_MenuItem
);
555 if (node
.getRepository().getFullBranch().equals(
557 // no checkout on current branch
558 checkout
.setEnabled(false);
560 } catch (IOException e2
) {
564 checkout
.addSelectionListener(new SelectionAdapter() {
567 public void widgetSelected(SelectionEvent e
) {
568 checkoutBranch(node
, ref
.getLeaf().getName());
572 new MenuItem(men
, SWT
.SEPARATOR
);
574 createCreateBranchItem(men
, node
);
575 createDeleteBranchItem(men
, node
);
580 if (node
.getType() == RepositoryTreeNodeType
.LOCALBRANCHES
581 || node
.getType() == RepositoryTreeNodeType
.REMOTEBRANCHES
)
582 createCreateBranchItem(men
, node
);
584 // for Repository: import existing projects, remove, (delete), open
586 if (node
.getType() == RepositoryTreeNodeType
.REPO
) {
588 final Repository repo
= (Repository
) node
.getObject();
590 // TODO "import existing plug-in" menu item
592 MenuItem remove
= new MenuItem(men
, SWT
.PUSH
);
593 remove
.setText(UIText
.RepositoriesView_Remove_MenuItem
);
594 remove
.addSelectionListener(new SelectionAdapter() {
597 public void widgetSelected(SelectionEvent e
) {
599 List
<IProject
> projectsToDelete
= new ArrayList
<IProject
>();
600 File workDir
= repo
.getWorkDir();
601 final IPath wdPath
= new Path(workDir
.getAbsolutePath());
602 for (IProject prj
: ResourcesPlugin
.getWorkspace()
603 .getRoot().getProjects()) {
604 if (wdPath
.isPrefixOf(prj
.getLocation())) {
605 projectsToDelete
.add(prj
);
609 if (!projectsToDelete
.isEmpty()) {
611 confirmed
= confirmProjectDeletion(projectsToDelete
);
617 IWorkspaceRunnable wsr
= new IWorkspaceRunnable() {
619 public void run(IProgressMonitor monitor
)
620 throws CoreException
{
622 for (IProject prj
: ResourcesPlugin
.getWorkspace()
623 .getRoot().getProjects()) {
624 if (wdPath
.isPrefixOf(prj
.getLocation())) {
625 prj
.delete(false, false, monitor
);
629 removeDir(repo
.getDirectory());
635 ResourcesPlugin
.getWorkspace().run(wsr
,
636 ResourcesPlugin
.getWorkspace().getRoot(),
637 IWorkspace
.AVOID_UPDATE
,
638 new NullProgressMonitor());
639 } catch (CoreException e1
) {
640 Activator
.logError(e1
.getMessage(), e1
);
647 // TODO delete does not work because of file locks on .pack-files
648 // Shawn Pearce has added the following thoughts:
650 // Hmm. We probably can't active detect file locks on pack files on
652 // It would be nice if we could support a delete, but only if the
654 // reasonably believed to be not-in-use right now.
656 // Within EGit you might be able to check GitProjectData and its
657 // repositoryCache to
658 // see if the repository is open by this workspace. If it is, then
659 // we know we shouldn't
662 // Some coding might look like this:
664 // MenuItem deleteRepo = new MenuItem(men, SWT.PUSH);
665 // deleteRepo.setText("Delete");
666 // deleteRepo.addSelectionListener(new SelectionAdapter() {
669 // public void widgetSelected(SelectionEvent e) {
671 // boolean confirmed = MessageDialog.openConfirm(getSite()
672 // .getShell(), "Confirm",
673 // "This will delete the repository, continue?");
678 // IWorkspaceRunnable wsr = new IWorkspaceRunnable() {
680 // public void run(IProgressMonitor monitor)
681 // throws CoreException {
682 // File workDir = repos.get(0).getRepository()
685 // File gitDir = repos.get(0).getRepository()
688 // IPath wdPath = new Path(workDir.getAbsolutePath());
689 // for (IProject prj : ResourcesPlugin.getWorkspace()
690 // .getRoot().getProjects()) {
691 // if (wdPath.isPrefixOf(prj.getLocation())) {
692 // prj.delete(false, false, monitor);
696 // repos.get(0).getRepository().close();
698 // boolean deleted = deleteRecursively(gitDir, monitor);
700 // MessageDialog.openError(getSite().getShell(),
702 // "Could not delete Git Repository");
705 // deleted = deleteRecursively(workDir, monitor);
708 // .openError(getSite().getShell(),
710 // "Could not delete Git Working Directory");
713 // scheduleRefresh();
716 // private boolean deleteRecursively(File fileToDelete,
717 // IProgressMonitor monitor) {
718 // if (fileToDelete.isDirectory()) {
719 // for (File file : fileToDelete.listFiles()) {
720 // if (!deleteRecursively(file, monitor)) {
725 // monitor.setTaskName(fileToDelete.getAbsolutePath());
726 // boolean deleted = fileToDelete.delete();
728 // System.err.println("Could not delete "
729 // + fileToDelete.getAbsolutePath());
736 // ResourcesPlugin.getWorkspace().run(wsr,
737 // ResourcesPlugin.getWorkspace().getRoot(),
738 // IWorkspace.AVOID_UPDATE,
739 // new NullProgressMonitor());
740 // } catch (CoreException e1) {
741 // // TODO Exception handling
742 // e1.printStackTrace();
749 new MenuItem(men
, SWT
.SEPARATOR
);
751 createImportProjectItem(men
, repo
, repo
.getWorkDir().getPath());
753 new MenuItem(men
, SWT
.SEPARATOR
);
755 MenuItem openPropsView
= new MenuItem(men
, SWT
.PUSH
);
756 openPropsView
.setText(UIText
.RepositoriesView_OpenPropertiesMenu
);
757 openPropsView
.addSelectionListener(new SelectionAdapter() {
760 public void widgetSelected(SelectionEvent e
) {
762 PlatformUI
.getWorkbench().getActiveWorkbenchWindow()
763 .getActivePage().showView(
764 IPageLayout
.ID_PROP_SHEET
);
765 } catch (PartInitException e1
) {
772 new MenuItem(men
, SWT
.SEPARATOR
);
774 createCopyPathItem(men
, repo
.getDirectory().getPath());
777 if (node
.getType() == RepositoryTreeNodeType
.REMOTES
) {
779 MenuItem remoteConfig
= new MenuItem(men
, SWT
.PUSH
);
780 remoteConfig
.setText(UIText
.RepositoriesView_NewRemoteMenu
);
781 remoteConfig
.addSelectionListener(new SelectionAdapter() {
784 public void widgetSelected(SelectionEvent e
) {
786 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
787 new NewRemoteWizard(node
.getRepository()));
788 if (dlg
.open() == Window
.OK
)
796 if (node
.getType() == RepositoryTreeNodeType
.REMOTE
) {
798 final String configName
= (String
) node
.getObject();
800 RemoteConfig rconfig
;
802 rconfig
= new RemoteConfig(node
.getRepository().getConfig(),
804 } catch (URISyntaxException e2
) {
805 // TODO Exception handling
809 boolean fetchExists
= rconfig
!= null
810 && !rconfig
.getURIs().isEmpty();
811 boolean pushExists
= rconfig
!= null
812 && !rconfig
.getPushURIs().isEmpty();
815 MenuItem configureUrlFetch
= new MenuItem(men
, SWT
.PUSH
);
817 .setText(UIText
.RepositoriesView_CreateFetch_menu
);
819 configureUrlFetch
.addSelectionListener(new SelectionAdapter() {
822 public void widgetSelected(SelectionEvent e
) {
824 WizardDialog dlg
= new WizardDialog(getSite()
825 .getShell(), new ConfigureRemoteWizard(node
826 .getRepository(), configName
, false));
827 if (dlg
.open() == Window
.OK
)
836 MenuItem configureUrlPush
= new MenuItem(men
, SWT
.PUSH
);
839 .setText(UIText
.RepositoriesView_CreatePush_menu
);
841 configureUrlPush
.addSelectionListener(new SelectionAdapter() {
844 public void widgetSelected(SelectionEvent e
) {
846 WizardDialog dlg
= new WizardDialog(getSite()
847 .getShell(), new ConfigureRemoteWizard(node
848 .getRepository(), configName
, true));
849 if (dlg
.open() == Window
.OK
)
857 if (!fetchExists
|| !pushExists
)
858 // add a separator dynamically
859 new MenuItem(men
, SWT
.SEPARATOR
);
861 MenuItem removeRemote
= new MenuItem(men
, SWT
.PUSH
);
862 removeRemote
.setText(UIText
.RepositoriesView_RemoveRemoteMenu
);
863 removeRemote
.addSelectionListener(new SelectionAdapter() {
866 public void widgetSelected(SelectionEvent e
) {
868 boolean ok
= MessageDialog
870 getSite().getShell(),
871 UIText
.RepositoriesView_ConfirmDeleteRemoteHeader
,
874 UIText
.RepositoriesView_ConfirmDeleteRemoteMessage
,
877 RepositoryConfig config
= node
.getRepository()
879 config
.unsetSection(REMOTE
, configName
);
883 } catch (IOException e1
) {
884 Activator
.handleError(
885 UIText
.RepositoriesView_ErrorHeader
, e1
,
894 new MenuItem(men
, SWT
.SEPARATOR
);
896 MenuItem openPropsView
= new MenuItem(men
, SWT
.PUSH
);
897 openPropsView
.setText(UIText
.RepositoriesView_OpenPropertiesMenu
);
898 openPropsView
.addSelectionListener(new SelectionAdapter() {
901 public void widgetSelected(SelectionEvent e
) {
903 PlatformUI
.getWorkbench().getActiveWorkbenchWindow()
904 .getActivePage().showView(
905 IPageLayout
.ID_PROP_SHEET
);
906 } catch (PartInitException e1
) {
914 if (node
.getType() == RepositoryTreeNodeType
.FETCH
) {
916 final String configName
= (String
) node
.getParent().getObject();
918 MenuItem configureUrlFetch
= new MenuItem(men
, SWT
.PUSH
);
920 .setText(UIText
.RepositoriesView_ConfigureFetchMenu
);
922 configureUrlFetch
.addSelectionListener(new SelectionAdapter() {
925 public void widgetSelected(SelectionEvent e
) {
927 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
928 new ConfigureRemoteWizard(node
.getRepository(),
930 if (dlg
.open() == Window
.OK
)
937 MenuItem deleteFetch
= new MenuItem(men
, SWT
.PUSH
);
938 deleteFetch
.setText(UIText
.RepositoriesView_RemoveFetch_menu
);
939 deleteFetch
.addSelectionListener(new SelectionAdapter() {
942 public void widgetSelected(SelectionEvent e
) {
943 RepositoryConfig config
= node
.getRepository().getConfig();
944 config
.unset("remote", configName
, "url"); //$NON-NLS-1$ //$NON-NLS-2$
945 config
.unset("remote", configName
, "fetch"); //$NON-NLS-1$//$NON-NLS-2$
949 } catch (IOException e1
) {
950 MessageDialog
.openError(getSite().getShell(),
951 UIText
.RepositoriesView_ErrorHeader
, e1
960 if (node
.getType() == RepositoryTreeNodeType
.PUSH
) {
962 final String configName
= (String
) node
.getParent().getObject();
964 MenuItem configureUrlPush
= new MenuItem(men
, SWT
.PUSH
);
966 configureUrlPush
.setText(UIText
.RepositoriesView_ConfigurePushMenu
);
968 configureUrlPush
.addSelectionListener(new SelectionAdapter() {
971 public void widgetSelected(SelectionEvent e
) {
973 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
974 new ConfigureRemoteWizard(node
.getRepository(),
976 if (dlg
.open() == Window
.OK
)
982 MenuItem deleteFetch
= new MenuItem(men
, SWT
.PUSH
);
983 deleteFetch
.setText(UIText
.RepositoriesView_RemovePush_menu
);
984 deleteFetch
.addSelectionListener(new SelectionAdapter() {
987 public void widgetSelected(SelectionEvent e
) {
988 RepositoryConfig config
= node
.getRepository().getConfig();
989 config
.unset("remote", configName
, "pushurl"); //$NON-NLS-1$ //$NON-NLS-2$
990 config
.unset("remote", configName
, "push"); //$NON-NLS-1$ //$NON-NLS-2$
994 } catch (IOException e1
) {
995 MessageDialog
.openError(getSite().getShell(),
996 UIText
.RepositoriesView_ErrorHeader
, e1
1004 if (node
.getType() == RepositoryTreeNodeType
.FILE
) {
1006 final File file
= (File
) node
.getObject();
1008 MenuItem openInTextEditor
= new MenuItem(men
, SWT
.PUSH
);
1010 .setText(UIText
.RepositoriesView_OpenInTextEditor_menu
);
1011 openInTextEditor
.addSelectionListener(new SelectionAdapter() {
1014 public void widgetSelected(SelectionEvent e
) {
1020 new MenuItem(men
, SWT
.SEPARATOR
);
1021 createCopyPathItem(men
, file
.getPath());
1024 if (node
.getType() == RepositoryTreeNodeType
.WORKINGDIR
) {
1025 String path
= node
.getRepository().getWorkDir().getAbsolutePath();
1026 createImportProjectItem(men
, node
.getRepository(), path
);
1027 new MenuItem(men
, SWT
.SEPARATOR
);
1028 createCopyPathItem(men
, path
);
1031 if (node
.getType() == RepositoryTreeNodeType
.FOLDER
) {
1032 String path
= ((File
) node
.getObject()).getPath();
1033 createImportProjectItem(men
, node
.getRepository(), path
);
1034 new MenuItem(men
, SWT
.SEPARATOR
);
1035 createCopyPathItem(men
, path
);
1040 private void createCopyPathItem(Menu men
, final String path
) {
1043 copyPath
= new MenuItem(men
, SWT
.PUSH
);
1044 copyPath
.setText(UIText
.RepositoriesView_CopyPathToClipboardMenu
);
1045 copyPath
.addSelectionListener(new SelectionAdapter() {
1048 public void widgetSelected(SelectionEvent e
) {
1049 Clipboard clipboard
= new Clipboard(null);
1050 TextTransfer textTransfer
= TextTransfer
.getInstance();
1051 Transfer
[] transfers
= new Transfer
[] { textTransfer
};
1052 Object
[] data
= new Object
[] { path
};
1053 clipboard
.setContents(data
, transfers
);
1054 clipboard
.dispose();
1061 private void createCreateBranchItem(Menu men
, final RepositoryTreeNode node
) {
1063 final boolean remoteMode
;
1065 if (node
.getType() == RepositoryTreeNodeType
.REF
) {
1066 remoteMode
= node
.getParent().getType() == RepositoryTreeNodeType
.REMOTEBRANCHES
;
1067 ref
= (Ref
) node
.getObject();
1068 } else if (node
.getType() == RepositoryTreeNodeType
.LOCALBRANCHES
) {
1071 } else if (node
.getType() == RepositoryTreeNodeType
.REMOTEBRANCHES
) {
1077 MenuItem createLocal
= new MenuItem(men
, SWT
.PUSH
);
1079 createLocal
.setText(UIText
.RepositoriesView_NewRemoteBranchMenu
);
1081 createLocal
.setText(UIText
.RepositoriesView_NewLocalBranchMenu
);
1083 createLocal
.addSelectionListener(new SelectionAdapter() {
1086 public void widgetSelected(SelectionEvent e
) {
1088 Wizard wiz
= new Wizard() {
1091 public void addPages() {
1092 addPage(new CreateBranchPage(node
.getRepository(), ref
,
1094 setWindowTitle(UIText
.RepositoriesView_NewBranchTitle
);
1098 public boolean performFinish() {
1101 getContainer().run(false, true,
1102 new IRunnableWithProgress() {
1104 public void run(IProgressMonitor monitor
)
1105 throws InvocationTargetException
,
1106 InterruptedException
{
1107 CreateBranchPage cp
= (CreateBranchPage
) getPages()[0];
1109 cp
.createBranch(monitor
);
1110 } catch (CoreException ce
) {
1111 throw new InvocationTargetException(
1113 } catch (IOException ioe
) {
1114 throw new InvocationTargetException(
1120 } catch (InvocationTargetException ite
) {
1123 UIText
.RepositoriesView_BranchCreationFailureMessage
,
1124 ite
.getCause(), true);
1126 } catch (InterruptedException ie
) {
1132 if (new WizardDialog(getSite().getShell(), wiz
).open() == Window
.OK
)
1140 private void createDeleteBranchItem(Menu men
, final RepositoryTreeNode node
) {
1142 final Ref ref
= (Ref
) node
.getObject();
1144 MenuItem deleteBranch
= new MenuItem(men
, SWT
.PUSH
);
1145 deleteBranch
.setText(UIText
.RepositoriesView_DeleteBranchMenu
);
1148 if (node
.getRepository().getFullBranch().equals(ref
.getName())) {
1149 deleteBranch
.setEnabled(false);
1151 } catch (IOException e2
) {
1155 deleteBranch
.addSelectionListener(new SelectionAdapter() {
1158 public void widgetSelected(SelectionEvent e
) {
1162 getSite().getShell(),
1163 UIText
.RepositoriesView_ConfirmDeleteTitle
,
1166 UIText
.RepositoriesView_ConfirmBranchDeletionMessage
,
1171 new ProgressMonitorDialog(getSite().getShell()).run(false,
1172 false, new IRunnableWithProgress() {
1174 public void run(IProgressMonitor monitor
)
1175 throws InvocationTargetException
,
1176 InterruptedException
{
1179 RefUpdate op
= node
.getRepository()
1180 .updateRef(ref
.getName());
1181 op
.setRefLogMessage("branch deleted", //$NON-NLS-1$
1183 // we set the force update in order
1184 // to avoid having this rejected
1185 // due to minor issues
1186 op
.setForceUpdate(true);
1189 } catch (IOException ioe
) {
1190 throw new InvocationTargetException(ioe
);
1195 } catch (InvocationTargetException e1
) {
1198 UIText
.RepositoriesView_BranchDeletionFailureMessage
,
1199 e1
.getCause(), true);
1200 e1
.printStackTrace();
1201 } catch (InterruptedException e1
) {
1210 private void openFile(File file
) {
1211 IFileStore store
= EFS
.getLocalFileSystem().getStore(
1212 new Path(file
.getAbsolutePath()));
1214 // TODO do we need a read-only editor here?
1215 IDE
.openEditor(getSite().getPage(),
1216 new FileStoreEditorInput(store
),
1217 EditorsUI
.DEFAULT_TEXT_EDITOR_ID
);
1218 } catch (PartInitException e
) {
1219 Activator
.handleError(UIText
.RepositoriesView_Error_WindowTitle
, e
,
1224 private void checkoutBranch(final RepositoryTreeNode node
,
1225 final String refName
) {
1226 // for the sake of UI responsiveness, let's start a job
1227 Job job
= new Job(NLS
.bind(UIText
.RepositoriesView_CheckingOutMessage
,
1231 protected IStatus
run(IProgressMonitor monitor
) {
1233 Repository repo
= node
.getRepository();
1235 final BranchOperation op
= new BranchOperation(repo
, refName
);
1236 IWorkspaceRunnable wsr
= new IWorkspaceRunnable() {
1238 public void run(IProgressMonitor myMonitor
)
1239 throws CoreException
{
1240 op
.execute(myMonitor
);
1245 ResourcesPlugin
.getWorkspace().run(wsr
,
1246 ResourcesPlugin
.getWorkspace().getRoot(),
1247 IWorkspace
.AVOID_UPDATE
, monitor
);
1249 } catch (CoreException e1
) {
1250 return new Status(IStatus
.ERROR
, Activator
.getPluginId(),
1251 e1
.getMessage(), e1
);
1254 return Status
.OK_STATUS
;
1262 private void createImportProjectItem(Menu men
, final Repository repo
,
1263 final String path
) {
1265 MenuItem startWizard
;
1266 startWizard
= new MenuItem(men
, SWT
.PUSH
);
1267 startWizard
.setText(UIText
.RepositoriesView_ImportProjectsMenu
);
1268 startWizard
.addSelectionListener(new SelectionAdapter() {
1271 public void widgetSelected(SelectionEvent e
) {
1272 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
1273 new GitCreateProjectViaWizardWizard(repo
, path
));
1274 if (dlg
.open() == Window
.OK
)
1281 // we could start the ImportWizard here,
1282 // unfortunately, this fails within a wizard
1283 // startWizard = new MenuItem(men, SWT.PUSH);
1284 // startWizard.setText("Start the Import wizard...");
1285 // startWizard.addSelectionListener(new SelectionAdapter() {
1288 // public void widgetSelected(SelectionEvent e) {
1290 // IHandlerService handlerService = (IHandlerService) getSite()
1291 // .getWorkbenchWindow().getWorkbench().getService(
1292 // IHandlerService.class);
1295 // handlerService.executeCommand("org.eclipse.ui.file.import", //$NON-NLS-1$
1297 // } catch (ExecutionException e1) {
1298 // Activator.handleError(e1.getMessage(), e1, true);
1299 // } catch (NotDefinedException e1) {
1300 // Activator.handleError(e1.getMessage(), e1, true);
1301 // } catch (NotEnabledException e1) {
1302 // Activator.handleError(e1.getMessage(), e1, true);
1303 // } catch (NotHandledException e1) {
1304 // Activator.handleError(e1.getMessage(), e1, true);
1311 private void addActionsToToolbar() {
1312 importAction
= new Action(UIText
.RepositoriesView_Import_Button
) {
1316 WizardDialog dlg
= new WizardDialog(getSite().getShell(),
1317 new GitCloneWizard());
1318 if (dlg
.open() == Window
.OK
)
1322 importAction
.setToolTipText(UIText
.RepositoriesView_Clone_Tooltip
);
1324 importAction
.setImageDescriptor(UIIcons
.CLONEGIT
);
1326 getViewSite().getActionBars().getToolBarManager().add(importAction
);
1328 addAction
= new Action(UIText
.RepositoriesView_Add_Button
) {
1332 RepositorySearchDialog sd
= new RepositorySearchDialog(
1333 getSite().getShell(), getDirs());
1334 if (sd
.open() == Window
.OK
) {
1335 Set
<String
> dirs
= new HashSet
<String
>();
1336 dirs
.addAll(getDirs());
1337 if (dirs
.addAll(sd
.getDirectories()))
1344 addAction
.setToolTipText(UIText
.RepositoriesView_AddRepository_Tooltip
);
1346 addAction
.setImageDescriptor(UIIcons
.NEW_REPOSITORY
);
1348 getViewSite().getActionBars().getToolBarManager().add(addAction
);
1350 linkWithSelectionAction
= new Action(
1351 UIText
.RepositoriesView_LinkWithSelection_action
,
1352 IAction
.AS_CHECK_BOX
) {
1356 IEclipsePreferences prefs
= getPrefs();
1357 prefs
.putBoolean(PREFS_SYNCED
, isChecked());
1360 } catch (BackingStoreException e
) {
1364 ISelectionService srv
= (ISelectionService
) getSite()
1365 .getService(ISelectionService
.class);
1366 reactOnSelection(srv
.getSelection());
1373 linkWithSelectionAction
1374 .setToolTipText(UIText
.RepositoriesView_LinkWithSelection_action
);
1376 linkWithSelectionAction
.setImageDescriptor(UIIcons
.ELCL16_SYNCED
);
1378 linkWithSelectionAction
.setChecked(getPrefs().getBoolean(PREFS_SYNCED
,
1381 getViewSite().getActionBars().getToolBarManager().add(
1382 linkWithSelectionAction
);
1384 refreshAction
= new Action(UIText
.RepositoriesView_Refresh_Button
) {
1392 refreshAction
.setImageDescriptor(UIIcons
.ELCL16_REFRESH
);
1394 getViewSite().getActionBars().getToolBarManager().add(refreshAction
);
1396 IAction collapseAllAction
= new Action(
1397 UIText
.RepositoriesView_CollapseAllMenu
) {
1405 // copy and paste are global actions; we just implement them
1406 // and register them with the global action handler
1407 // we enable/disable them upon tree selection changes
1409 copyAction
= new Action("") { //$NON-NLS-1$
1413 // for REPO, WORKINGDIR, FILE, FOLDER: copy directory
1414 IStructuredSelection sel
= (IStructuredSelection
) tv
1416 if (sel
.size() == 1) {
1417 RepositoryTreeNode node
= (RepositoryTreeNode
) sel
1420 if (node
.getType() == RepositoryTreeNodeType
.REPO
) {
1421 dir
= node
.getRepository().getDirectory().getPath();
1422 } else if (node
.getType() == RepositoryTreeNodeType
.FILE
1423 || node
.getType() == RepositoryTreeNodeType
.FOLDER
) {
1424 dir
= ((File
) node
.getObject()).getPath();
1425 } else if (node
.getType() == RepositoryTreeNodeType
.WORKINGDIR
) {
1426 dir
= node
.getRepository().getWorkDir().getPath();
1429 Clipboard clip
= null;
1431 clip
= new Clipboard(getSite().getShell()
1434 .setContents(new Object
[] { dir
},
1435 new Transfer
[] { TextTransfer
1439 // we must dispose ourselves
1447 copyAction
.setEnabled(false);
1449 getViewSite().getActionBars().setGlobalActionHandler(
1450 ActionFactory
.COPY
.getId(), copyAction
);
1452 pasteAction
= new Action("") { //$NON-NLS-1$
1456 // we check if the pasted content is a directory
1457 // repository location and try to add this
1458 String errorMessage
= null;
1460 Clipboard clip
= null;
1462 clip
= new Clipboard(getSite().getShell().getDisplay());
1463 String content
= (String
) clip
.getContents(TextTransfer
1465 if (content
== null) {
1466 errorMessage
= UIText
.RepositoriesView_NothingToPasteMessage
;
1470 File file
= new File(content
);
1471 if (!file
.exists() || !file
.isDirectory()) {
1472 errorMessage
= UIText
.RepositoriesView_ClipboardContentNotDirectoryMessage
;
1476 if (!RepositoryCache
.FileKey
.isGitRepository(file
)) {
1479 UIText
.RepositoriesView_ClipboardContentNoGitRepoMessage
,
1487 errorMessage
= NLS
.bind(
1488 UIText
.RepositoriesView_PasteRepoAlreadyThere
,
1492 // we must dispose ourselves
1494 if (errorMessage
!= null)
1496 MessageDialog
.openWarning(getSite().getShell(),
1497 UIText
.RepositoriesView_PasteFailureTitle
,
1504 collapseAllAction
.setImageDescriptor(UIIcons
.COLLAPSEALL
);
1506 getViewSite().getActionBars().getToolBarManager()
1507 .add(collapseAllAction
);
1509 getViewSite().getActionBars().setGlobalActionHandler(
1510 ActionFactory
.PASTE
.getId(), pasteAction
);
1515 * @return the preferences
1517 protected static IEclipsePreferences
getPrefs() {
1518 return new InstanceScope().getNode(Activator
.getPluginId());
1522 public void dispose() {
1523 // make sure to cancel the refresh job
1524 if (this.scheduledJob
!= null) {
1525 this.scheduledJob
.cancel();
1526 this.scheduledJob
= null;
1532 * Schedules a refreh
1534 public void scheduleRefresh() {
1536 Job job
= new Job("Refreshing Git Repositories view") { //$NON-NLS-1$
1539 protected IStatus
run(IProgressMonitor monitor
) {
1541 final List
<RepositoryTreeNode
<Repository
>> input
;
1543 input
= getRepositoriesFromDirs(monitor
);
1544 } catch (InterruptedException e
) {
1545 return new Status(IStatus
.ERROR
, Activator
.getPluginId(), e
1549 boolean needsNewInput
= tv
.getInput() == null;
1550 List oldInput
= (List
) tv
.getInput();
1552 needsNewInput
= oldInput
.size() != input
.size();
1554 if (!needsNewInput
) {
1555 for (int i
= 0; i
< input
.size(); i
++) {
1556 needsNewInput
= !input
.get(i
).equals(oldInput
.get(i
));
1562 final boolean updateInput
= needsNewInput
;
1564 Display
.getDefault().syncExec(new Runnable() {
1567 // keep expansion state and selection so that we can
1570 Object
[] expanded
= tv
.getExpandedElements();
1571 IStructuredSelection sel
= (IStructuredSelection
) tv
1577 tv
.setExpandedElements(expanded
);
1579 Object selected
= sel
.getFirstElement();
1580 if (selected
!= null)
1581 tv
.reveal(selected
);
1583 IViewPart part
= PlatformUI
.getWorkbench()
1584 .getActiveWorkbenchWindow().getActivePage()
1585 .findView(IPageLayout
.ID_PROP_SHEET
);
1587 PropertySheet sheet
= (PropertySheet
) part
;
1588 PropertySheetPage page
= (PropertySheetPage
) sheet
1595 return new Status(IStatus
.OK
, Activator
.getPluginId(), ""); //$NON-NLS-1$
1600 job
.setSystem(true);
1602 IWorkbenchSiteProgressService service
= (IWorkbenchSiteProgressService
) getSite()
1603 .getService(IWorkbenchSiteProgressService
.class);
1605 service
.schedule(job
);
1612 * Adds a directory to the list if it is not already there
1615 * @return see {@link Collection#add(Object)}
1617 public static boolean addDir(File file
) {
1621 dirString
= file
.getCanonicalPath();
1622 } catch (IOException e
) {
1623 dirString
= file
.getAbsolutePath();
1626 List
<String
> dirStrings
= getDirs();
1627 if (dirStrings
.contains(dirString
)) {
1630 Set
<String
> dirs
= new HashSet
<String
>();
1631 dirs
.addAll(dirStrings
);
1632 dirs
.add(dirString
);
1639 * Converts the directories as configured for this view into a list of
1640 * {@link Repository} objects suitable for the tree content provider
1642 * TODO move to some utility class
1645 * @return a list of nodes
1646 * @throws InterruptedException
1648 public static List
<RepositoryTreeNode
<Repository
>> getRepositoriesFromDirs(
1649 IProgressMonitor monitor
) throws InterruptedException
{
1651 List
<String
> gitDirStrings
= getDirs();
1652 List
<RepositoryTreeNode
<Repository
>> input
= new ArrayList
<RepositoryTreeNode
<Repository
>>();
1654 for (String dirString
: gitDirStrings
) {
1655 if (monitor
!= null && monitor
.isCanceled()) {
1656 throw new InterruptedException(
1657 UIText
.RepositoriesView_ActionCanceled_Message
);
1660 File dir
= new File(dirString
);
1661 if (dir
.exists() && dir
.isDirectory()) {
1662 Repository repo
= new Repository(dir
);
1663 RepositoryTreeNode
<Repository
> node
= new RepositoryTreeNode
<Repository
>(
1664 null, RepositoryTreeNodeType
.REPO
, repo
, repo
);
1667 } catch (IOException e
) {
1668 IStatus error
= new Status(IStatus
.ERROR
, Activator
1669 .getPluginId(), e
.getMessage(), e
);
1670 Activator
.getDefault().getLog().log(error
);
1673 Collections
.sort(input
);
1677 private static void saveDirs(Set
<String
> gitDirStrings
) {
1678 StringBuilder sb
= new StringBuilder();
1679 for (String gitDirString
: gitDirStrings
) {
1680 sb
.append(gitDirString
);
1681 sb
.append(File
.pathSeparatorChar
);
1684 IEclipsePreferences prefs
= getPrefs();
1685 prefs
.put(PREFS_DIRECTORIES
, sb
.toString());
1688 } catch (BackingStoreException e
) {
1689 IStatus error
= new Status(IStatus
.ERROR
, Activator
.getPluginId(),
1691 Activator
.getDefault().getLog().log(error
);
1696 public void setFocus() {
1697 tv
.getTree().setFocus();
1700 @SuppressWarnings("boxing")
1701 private boolean confirmProjectDeletion(List
<IProject
> projectsToDelete
) {
1703 confirmed
= MessageDialog
1705 getSite().getShell(),
1706 UIText
.RepositoriesView_ConfirmProjectDeletion_WindowTitle
,
1709 UIText
.RepositoriesView_ConfirmProjectDeletion_Question
,
1710 projectsToDelete
.size()));
1714 public void addSelectionChangedListener(ISelectionChangedListener listener
) {
1715 selectionListeners
.add(listener
);
1718 public ISelection
getSelection() {
1719 return currentSelection
;
1722 public void removeSelectionChangedListener(
1723 ISelectionChangedListener listener
) {
1724 selectionListeners
.remove(listener
);
1728 public void setSelection(ISelection selection
) {
1729 currentSelection
= selection
;
1730 for (ISelectionChangedListener listener
: selectionListeners
) {
1731 listener
.selectionChanged(new SelectionChangedEvent(
1732 RepositoriesView
.this, selection
));
1737 * Opens the tree and marks the folder to which a project is pointing
1742 @SuppressWarnings("unchecked")
1743 public void showResource(final IResource resource
) {
1744 IProject project
= resource
.getProject();
1745 RepositoryMapping mapping
= RepositoryMapping
.getMapping(project
);
1746 if (mapping
== null)
1749 if (addDir(mapping
.getRepository().getDirectory())) {
1753 boolean doSetSelection
= false;
1755 if (this.scheduledJob
!= null) {
1756 int state
= this.scheduledJob
.getState();
1757 if (state
== Job
.WAITING
|| state
== Job
.RUNNING
) {
1758 this.scheduledJob
.addJobChangeListener(new JobChangeAdapter() {
1761 public void done(IJobChangeEvent event
) {
1762 showResource(resource
);
1766 doSetSelection
= true;
1770 if (doSetSelection
) {
1771 RepositoriesViewContentProvider cp
= (RepositoriesViewContentProvider
) tv
1772 .getContentProvider();
1773 RepositoryTreeNode currentNode
= null;
1774 Object
[] repos
= cp
.getElements(tv
.getInput());
1775 for (Object repo
: repos
) {
1776 RepositoryTreeNode node
= (RepositoryTreeNode
) repo
;
1777 // TODO equals implementation of Repository?
1778 if (mapping
.getRepository().getDirectory().equals(
1779 ((Repository
) node
.getObject()).getDirectory())) {
1780 for (Object child
: cp
.getChildren(node
)) {
1781 RepositoryTreeNode childNode
= (RepositoryTreeNode
) child
;
1782 if (childNode
.getType() == RepositoryTreeNodeType
.WORKINGDIR
) {
1783 currentNode
= childNode
;
1791 IPath relPath
= new Path(mapping
.getRepoRelativePath(resource
));
1793 for (String segment
: relPath
.segments()) {
1794 for (Object child
: cp
.getChildren(currentNode
)) {
1795 RepositoryTreeNode
<File
> childNode
= (RepositoryTreeNode
<File
>) child
;
1796 if (childNode
.getObject().getName().equals(segment
)) {
1797 currentNode
= childNode
;
1803 final RepositoryTreeNode selNode
= currentNode
;
1805 Display
.getDefault().asyncExec(new Runnable() {
1808 tv
.setSelection(new StructuredSelection(selNode
), true);
1816 public boolean show(ShowInContext context
) {
1817 ISelection selection
= context
.getSelection();
1818 if (selection
instanceof IStructuredSelection
) {
1819 IStructuredSelection ss
= (IStructuredSelection
) selection
;
1820 if (ss
.size() == 1) {
1821 Object element
= ss
.getFirstElement();
1822 if (element
instanceof IAdaptable
) {
1823 IResource resource
= (IResource
) ((IAdaptable
) element
)
1824 .getAdapter(IResource
.class);
1825 if (resource
!= null) {
1826 showResource(resource
);