From 051a8c779ac2fd7ad95373f10555d4a513968bff Mon Sep 17 00:00:00 2001 From: Mathias Kinzler Date: Tue, 18 May 2010 18:52:48 +0200 Subject: [PATCH] Git Repositories View: auto-refresh This addresses the bug below, but in a more general manner: a periodic (every 10 seconds) job will look for Repository changes and refresh the tree if such changes are found. Bug: 312993 Change-Id: Iee00e1ca7fbf865e4fd59acc904803ded933b3df Signed-off-by: Mathias Kinzler Signed-off-by: Matthias Sohn --- .../egit/ui/internal/clone/GitCloneWizard.java | 16 -- .../ui/internal/repository/RepositoriesView.java | 211 ++++++++++++++------- 2 files changed, 145 insertions(+), 82 deletions(-) diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java index 163561b0..b3ec1123 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clone/GitCloneWizard.java @@ -34,8 +34,6 @@ import org.eclipse.jface.wizard.Wizard; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.transport.URIish; import org.eclipse.osgi.util.NLS; -import org.eclipse.ui.IViewPart; -import org.eclipse.ui.PlatformUI; /** * Import Git Repository Wizard. A front end to a git clone operation. @@ -141,15 +139,6 @@ public class GitCloneWizard extends Wizard { return false; } - final RepositoriesView view; - IViewPart vp = PlatformUI.getWorkbench().getActiveWorkbenchWindow() - .getActivePage().findView(RepositoriesView.VIEW_ID); - if (vp != null) { - view = (RepositoriesView) vp; - } else { - view = null; - } - final CloneOperation op = new CloneOperation(uri, allSelected, selectedBranches, workdir, branch, remoteName); @@ -164,9 +153,6 @@ public class GitCloneWizard extends Wizard { op.run(monitor); RepositorySelectionPage.saveUriInPrefs(uri.toString()); RepositoriesView.addDir(op.getGitDir()); - if (view != null) - view.scheduleRefresh(); - return Status.OK_STATUS; } catch (InterruptedException e) { return Status.CANCEL_STATUS; @@ -197,8 +183,6 @@ public class GitCloneWizard extends Wizard { RepositorySelectionPage.saveUriInPrefs(uri.toString()); RepositoriesView.addDir(op.getGitDir()); - if (view != null) - view.scheduleRefresh(); return true; } catch (InterruptedException e) { MessageDialog.openInformation(getShell(), diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java index 1a1be450..703421c0 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java @@ -72,11 +72,14 @@ import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.Wizard; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.IndexChangedEvent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefsChangedEvent; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache; import org.eclipse.jgit.lib.RepositoryConfig; +import org.eclipse.jgit.lib.RepositoryListener; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; @@ -127,9 +130,7 @@ import org.osgi.service.prefs.BackingStoreException; * Implements {@link ISelectionProvider} in order to integrate with the * Properties view. *

- * TODO - *

  • Clarification whether to show projects, perhaps configurable switch
  • - * + * This periodically refreshes itself in order to react on Repository changes. */ public class RepositoriesView extends ViewPart implements ISelectionProvider, IShowInTarget { @@ -154,10 +155,14 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, private final List selectionListeners = new ArrayList(); + private final static long AUTO_REFRESH_INTERVAL_MILLISECONDS = 10000l; + private ISelection currentSelection = new StructuredSelection(); private Job scheduledJob; + private Job autoRefreshJob; + private TreeViewer tv; private IAction importAction; @@ -185,7 +190,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, while (tok.hasMoreTokens()) { String dirName = tok.nextToken(); File testFile = new File(dirName); - if (testFile.exists()) { + if (testFile.exists() && !resultStrings.contains(dirName)) { resultStrings.add(dirName); } } @@ -342,6 +347,20 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, scheduleRefresh(); + // schedule the auto-refresh job + autoRefreshJob = new Job("Git Repositories View Auto-Refresh") { //$NON-NLS-1$ + + @Override + protected IStatus run(IProgressMonitor monitor) { + scheduleRefresh(); + schedule(AUTO_REFRESH_INTERVAL_MILLISECONDS); + return Status.OK_STATUS; + } + }; + + autoRefreshJob.setSystem(true); + autoRefreshJob.schedule(AUTO_REFRESH_INTERVAL_MILLISECONDS); + ISelectionService srv = (ISelectionService) getSite().getService( ISelectionService.class); srv.addPostSelectionListener(new ISelectionListener() { @@ -718,7 +737,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, WizardDialog dlg = new WizardDialog(getSite().getShell(), new NewRemoteWizard(node.getRepository())); if (dlg.open() == Window.OK) - scheduleRefresh(); + tv.refresh(); } @@ -757,7 +776,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, .getShell(), new ConfigureRemoteWizard(node .getRepository(), configName, false)); if (dlg.open() == Window.OK) - scheduleRefresh(); + tv.refresh(); } @@ -779,7 +798,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, .getShell(), new ConfigureRemoteWizard(node .getRepository(), configName, true)); if (dlg.open() == Window.OK) - scheduleRefresh(); + tv.refresh(); } @@ -811,7 +830,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, config.unsetSection(REMOTE, configName); try { config.save(); - scheduleRefresh(); + tv.refresh(); } catch (IOException e1) { Activator.handleError( UIText.RepositoriesView_ErrorHeader, e1, @@ -860,7 +879,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, new ConfigureRemoteWizard(node.getRepository(), configName, false)); if (dlg.open() == Window.OK) - scheduleRefresh(); + tv.refresh(); } @@ -877,7 +896,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, config.unset("remote", configName, "fetch"); //$NON-NLS-1$//$NON-NLS-2$ try { config.save(); - scheduleRefresh(); + tv.refresh(); } catch (IOException e1) { MessageDialog.openError(getSite().getShell(), UIText.RepositoriesView_ErrorHeader, e1 @@ -906,7 +925,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, new ConfigureRemoteWizard(node.getRepository(), configName, true)); if (dlg.open() == Window.OK) - scheduleRefresh(); + tv.refresh(); } }); @@ -922,7 +941,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, config.unset("remote", configName, "push"); //$NON-NLS-1$ //$NON-NLS-2$ try { config.save(); - scheduleRefresh(); + tv.refresh(); } catch (IOException e1) { MessageDialog.openError(getSite().getShell(), UIText.RepositoriesView_ErrorHeader, e1 @@ -1084,7 +1103,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, } }; if (new WizardDialog(getSite().getShell(), wiz).open() == Window.OK) - scheduleRefresh(); + tv.refresh(); } }); @@ -1133,7 +1152,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, // due to minor issues op.setForceUpdate(true); op.delete(); - scheduleRefresh(); + tv.refresh(); } catch (IOException ioe) { throw new InvocationTargetException(ioe); } @@ -1193,7 +1212,13 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, ResourcesPlugin.getWorkspace().run(wsr, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, monitor); - scheduleRefresh(); + Display.getDefault().syncExec(new Runnable() { + + public void run() { + tv.refresh(); + } + }); + } catch (CoreException e1) { return new Status(IStatus.ERROR, Activator.getPluginId(), e1.getMessage(), e1); @@ -1219,9 +1244,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, public void widgetSelected(SelectionEvent e) { WizardDialog dlg = new WizardDialog(getSite().getShell(), new GitCreateProjectViaWizardWizard(repo, path)); - if (dlg.open() == Window.OK) - scheduleRefresh(); - + dlg.open(); } }); @@ -1472,75 +1495,127 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, this.scheduledJob.cancel(); this.scheduledJob = null; } + // and the auto refresh job, too + if (this.autoRefreshJob != null) { + this.autoRefreshJob.cancel(); + this.autoRefreshJob = null; + } super.dispose(); } + @SuppressWarnings("unchecked") + private boolean checkForRepositoryChanges() { + + if (tv.getInput() == null) + return false; + + final Set reposToRefresh = new HashSet(); + + RepositoryListener listener = new RepositoryListener() { + + public void refsChanged(RefsChangedEvent e) { + reposToRefresh.add(e.getRepository()); + } + + public void indexChanged(IndexChangedEvent e) { + reposToRefresh.add(e.getRepository()); + } + }; + + List> input = (List>) tv + .getInput(); + + for (final RepositoryTreeNode node : input) { + + Repository repository = node.getRepository(); + repository.addRepositoryChangedListener(listener); + try { + repository.scanForRepoChanges(); + } catch (IOException e1) { + // ignore + } finally { + repository.removeRepositoryChangedListener(listener); + } + } + + return !reposToRefresh.isEmpty(); + } + /** - * Schedules a refreh + * Schedules a refresh */ - public void scheduleRefresh() { + private void scheduleRefresh() { Job job = new Job("Refreshing Git Repositories view") { //$NON-NLS-1$ + @SuppressWarnings("unchecked") @Override protected IStatus run(IProgressMonitor monitor) { - - final List> input; - try { - input = getRepositoriesFromDirs(monitor); - } catch (InterruptedException e) { - return new Status(IStatus.ERROR, Activator.getPluginId(), e - .getMessage(), e); - } + // first, let's check if the list of Directories has changed + final List directories = getDirs(); boolean needsNewInput = tv.getInput() == null; - List oldInput = (List) tv.getInput(); + List> oldInput = (List) tv + .getInput(); if (!needsNewInput) - needsNewInput = oldInput.size() != input.size(); + needsNewInput = oldInput.size() != directories.size(); if (!needsNewInput) { - for (int i = 0; i < input.size(); i++) { - needsNewInput = !input.get(i).equals(oldInput.get(i)); - if (needsNewInput) - break; + List oldDirectories = new ArrayList(); + for (RepositoryTreeNode node : oldInput) { + oldDirectories.add(node.getRepository().getDirectory() + .getPath()); } + needsNewInput = !directories.containsAll(oldDirectories); } final boolean updateInput = needsNewInput; - - Display.getDefault().syncExec(new Runnable() { - - public void run() { - // keep expansion state and selection so that we can - // restore the tree - // after update - Object[] expanded = tv.getExpandedElements(); - IStructuredSelection sel = (IStructuredSelection) tv - .getSelection(); - if (updateInput) - tv.setInput(input); - else - tv.refresh(); - tv.setExpandedElements(expanded); - - Object selected = sel.getFirstElement(); - if (selected != null) - tv.reveal(selected); - - IViewPart part = PlatformUI.getWorkbench() - .getActiveWorkbenchWindow().getActivePage() - .findView(IPageLayout.ID_PROP_SHEET); - if (part != null) { - PropertySheet sheet = (PropertySheet) part; - PropertySheetPage page = (PropertySheetPage) sheet - .getCurrentPage(); - page.refresh(); - } + final List newInput; + if (updateInput) + try { + newInput = getRepositoriesFromDirs(monitor); + } catch (InterruptedException e) { + return new Status(IStatus.ERROR, Activator + .getPluginId(), e.getMessage(), e); } - }); - + else + newInput = null; + + // we only check for Repository changes if we don't + // have a new input + if (updateInput || checkForRepositoryChanges()) { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + // keep expansion state and selection so that we can + // restore the tree + // after update + Object[] expanded = tv.getExpandedElements(); + IStructuredSelection sel = (IStructuredSelection) tv + .getSelection(); + + if (updateInput) + tv.setInput(newInput); + else + tv.refresh(); + tv.setExpandedElements(expanded); + + Object selected = sel.getFirstElement(); + if (selected != null) + tv.reveal(selected); + + IViewPart part = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getActivePage() + .findView(IPageLayout.ID_PROP_SHEET); + if (part != null) { + PropertySheet sheet = (PropertySheet) part; + PropertySheetPage page = (PropertySheetPage) sheet + .getCurrentPage(); + page.refresh(); + } + } + }); + } return new Status(IStatus.OK, Activator.getPluginId(), ""); //$NON-NLS-1$ - } }; @@ -1607,6 +1682,10 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider, File dir = new File(dirString); if (dir.exists() && dir.isDirectory()) { Repository repo = new Repository(dir); + // reset repository change events here so that check for + // repository changes does not trigger an unnecessary + // refresh + repo.scanForRepoChanges(); RepositoryTreeNode node = new RepositoryTreeNode( null, RepositoryTreeNodeType.REPO, repo, repo); input.add(node); -- 2.11.4.GIT