From 77beda4de51a204507a4e22dd01fff4172919e33 Mon Sep 17 00:00:00 2001 From: Mathias Kinzler Date: Wed, 31 Mar 2010 23:17:30 +0200 Subject: Repositories View fixes/improvements 1: integrated Wim Jongman's suggestions for the Repository Search Dialog 2: added "Working Directory" node to reflect the file system structure of the repository 3: added "Show in Git Repositories View" action to Team menu to allow finding resources under Git-controlled projects in the view 4: implemented "Link to selection" checkbox in the view to allow keeping the selection in the project explorer in sync with the selection in the "Working Directory" subtree 5: the tree must be wide enough to show long directory names 6: integration with GitCloneWizard (automatic refresh of the view after cloning) 7: missing icon for the view added Bug: 301168 Change-Id: Ia46e24d30b4c3dc8221489cfc653d71eebf47156 Signed-off-by: Mathias Kinzler --- org.eclipse.egit.ui/META-INF/MANIFEST.MF | 3 +- org.eclipse.egit.ui/icons/elcl16/synced.gif | Bin 0 -> 160 bytes org.eclipse.egit.ui/icons/eview16/repo_rep.gif | Bin 0 -> 588 bytes org.eclipse.egit.ui/plugin.xml | 9 + .../src/org/eclipse/egit/ui/UIIcons.java | 3 + .../src/org/eclipse/egit/ui/UIText.java | 107 ++- .../actions/ShowInRepositoriesViewAction.java | 70 ++ .../egit/ui/internal/clone/GitCloneWizard.java | 19 + .../egit/ui/internal/components/RefSpecPage.java | 49 +- .../components/RepositorySelectionPage.java | 115 ++- .../internal/repository/ConfigureRemoteWizard.java | 188 +++- .../ui/internal/repository/RepositoriesView.java | 1016 ++++++++------------ .../RepositoriesViewContentProvider.java | 271 ++++++ .../repository/RepositoriesViewLabelProvider.java | 252 +++++ .../repository/RepositoryPropertySource.java | 29 +- .../repository/RepositoryRemotePropertySource.java | 5 +- .../repository/RepositorySearchDialog.java | 196 +++- .../ui/internal/repository/RepositoryTreeNode.java | 22 +- .../internal/repository/RepositoryViewUITexts.java | 108 --- .../internal/repository/SelectRemoteNamePage.java | 38 + .../repository/repositoryviewuitexts.properties | 27 - .../src/org/eclipse/egit/ui/uitext.properties | 42 +- 22 files changed, 1650 insertions(+), 919 deletions(-) create mode 100644 org.eclipse.egit.ui/icons/elcl16/synced.gif create mode 100644 org.eclipse.egit.ui/icons/eview16/repo_rep.gif create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ShowInRepositoriesViewAction.java create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java delete mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryViewUITexts.java delete mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/repositoryviewuitexts.properties diff --git a/org.eclipse.egit.ui/META-INF/MANIFEST.MF b/org.eclipse.egit.ui/META-INF/MANIFEST.MF index eca6df080f..d690eb61b4 100644 --- a/org.eclipse.egit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.egit.ui/META-INF/MANIFEST.MF @@ -19,7 +19,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)", org.eclipse.compare;bundle-version="[3.4.0,4.0.0)", org.eclipse.ui.ide;bundle-version="[3.4.0,4.0.0)", org.eclipse.jsch.ui;bundle-version="[1.1.100,2.0.0)", - org.eclipse.jsch.core;bundle-version="[1.1.100,2.0.0)" + org.eclipse.jsch.core;bundle-version="[1.1.100,2.0.0)", + org.eclipse.ui.editors;bundle-version="[3.4.0,4.0.0)" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 Import-Package: com.jcraft.jsch;version="[0.1.41,0.2.0)", diff --git a/org.eclipse.egit.ui/icons/elcl16/synced.gif b/org.eclipse.egit.ui/icons/elcl16/synced.gif new file mode 100644 index 0000000000..870934b693 Binary files /dev/null and b/org.eclipse.egit.ui/icons/elcl16/synced.gif differ diff --git a/org.eclipse.egit.ui/icons/eview16/repo_rep.gif b/org.eclipse.egit.ui/icons/eview16/repo_rep.gif new file mode 100644 index 0000000000..c13bea1ca4 Binary files /dev/null and b/org.eclipse.egit.ui/icons/eview16/repo_rep.gif differ diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml index 76719a6ee5..08c588552c 100644 --- a/org.eclipse.egit.ui/plugin.xml +++ b/org.eclipse.egit.ui/plugin.xml @@ -96,6 +96,14 @@ label="%ShowResourceInHistoryAction_label" menubarPath="team.main/group1" tooltip="%ShowResourceInHistoryAction_tooltip"/> + + diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java index c72d663890..2afc905c22 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java @@ -62,6 +62,8 @@ public class UIIcons { public static final ImageDescriptor ELCL16_CLEAR; /** Refresh icon */ public static final ImageDescriptor ELCL16_REFRESH; + /** Linked with icon */ + public static final ImageDescriptor ELCL16_SYNCED; /** Enabled, checked, checkbox image */ public static final ImageDescriptor CHECKBOX_ENABLED_CHECKED; @@ -129,6 +131,7 @@ public class UIIcons { ELCL16_TRASH = map("elcl16/trash.gif"); //$NON-NLS-1$ ELCL16_CLEAR = map("elcl16/clear.gif"); //$NON-NLS-1$ ELCL16_REFRESH = map("elcl16/refresh.gif"); //$NON-NLS-1$ + ELCL16_SYNCED = map("elcl16/synced.gif"); //$NON-NLS-1$ CHECKBOX_ENABLED_CHECKED = map("checkboxes/enabled_checked.gif"); //$NON-NLS-1$ CHECKBOX_ENABLED_UNCHECKED = map("checkboxes/enabled_unchecked.gif"); //$NON-NLS-1$ CHECKBOX_DISABLED_CHECKED = map("checkboxes/disabled_checked.gif"); //$NON-NLS-1$ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java index 95bc859992..f126cd7138 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java @@ -205,23 +205,38 @@ public class UIText extends NLS { public static String RepositoryRemotePropertySource_PushLabel; /** */ - public static String RepositoryRemotePropertySource_RemoteUrlLabel; + public static String RepositoryRemotePropertySource_RemoteFetchURL_label; + + /** */ + public static String RepositoryRemotePropertySource_RemotePushUrl_label; /** */ public static String RepositorySearchDialog_BrowseButton; + /** */ + public static String RepositorySearchDialog_DeepSearch_button; + /** */ public static String RepositorySearchDialog_DirectoryLabel; /** */ public static String RepositorySearchDialog_ErrorHeader; + /** */ + public static String RepositorySearchDialog_RepositoriesFound_message; + + /** */ + public static String RepositorySearchDialog_ScanningForRepositories_message; + /** */ public static String RepositorySearchDialog_SearchButton; /** */ public static String RepositorySearchDialog_SearchRepositoriesHeader; + /** */ + public static String RepositorySearchDialog_ToggleSelection_button; + /** */ public static String RepositorySelectionPage_BrowseLocalFile; @@ -1224,6 +1239,96 @@ public class UIText extends NLS { /** */ public static String Track_see_log; + /** */ + public static String RepositoriesView_ActionCanceled_Message; + + /** */ + public static String RepositoriesView_Add_Button; + + /** */ + public static String RepositoriesView_AddRepository_MenuItem; + + /** */ + public static String RepositoriesView_AddRepository_Tooltip; + + /** */ + public static String RepositoriesView_Branches_Nodetext; + + /** */ + public static String RepositoriesView_Checking_Message; + + /** */ + public static String RepositoriesView_CheckOut_MenuItem; + + /** */ + public static String RepositoriesView_Clone_Tooltip; + + /** */ + public static String RepositoriesView_ConfigureFetchMenu; + + /** */ + public static String RepositoriesView_ConfigurePushMenu; + + /** */ + public static String RepositoriesView_ConfirmDeleteRemoteHeader; + + /** */ + public static String RepositoriesView_ConfirmDeleteRemoteMessage; + + /** */ + public static String RepositoriesView_ConfirmProjectDeletion_Question; + + /** */ + public static String RepositoriesView_ConfirmProjectDeletion_WindowTitle; + + /** */ + public static String RepositoriesView_Error_WindowTitle; + + /** */ + public static String RepositoriesView_ErrorHeader; + + /** */ + public static String RepositoriesView_ExistingProjects_Nodetext; + + /** */ + public static String RepositoriesView_Import_Button; + + /** */ + public static String RepositoriesView_ImportExistingProjects_MenuItem; + + /** */ + public static String RepositoriesView_ImportProject_MenuItem; + + /** */ + public static String RepositoriesView_ImportRepository_MenuItem; + + /** */ + public static String RepositoriesView_LinkWithSelection_action; + + /** */ + public static String RepositoriesView_NewRemoteMenu; + + /** */ + public static String RepositoriesView_OpenInTextEditor_menu; + + /** */ + public static String RepositoriesView_OpenPropertiesMenu; + + /** */ + public static String RepositoriesView_Refresh_Button; + + /** */ + public static String RepositoriesView_RemotesNodeText; + + /** */ + public static String RepositoriesView_Remove_MenuItem; + + /** */ + public static String RepositoriesView_RemoveRemoteMenu; + + /** */ + public static String RepositoriesView_WorkingDir_treenode; + static { initializeMessages("org.eclipse.egit.ui.uitext", UIText.class); //$NON-NLS-1$ } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ShowInRepositoriesViewAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ShowInRepositoriesViewAction.java new file mode 100644 index 0000000000..c8495bbd6f --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ShowInRepositoriesViewAction.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mathias Kinzler (SAP AG) - initial implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.actions; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.egit.ui.Activator; +import org.eclipse.egit.ui.internal.repository.RepositoriesView; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +/** + * Shows a Project in the Repositories View + */ +public class ShowInRepositoriesViewAction implements IObjectActionDelegate { + + private IResource selectedResource = null; + + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + // nothing here + } + + public void run(IAction action) { + + if (selectedResource == null) { + return; + } + + IViewPart part; + try { + part = PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().showView(RepositoriesView.VIEW_ID); + } catch (PartInitException e) { + Activator.getDefault().getLog().log(e.getStatus()); + return; + } + + RepositoriesView view = (RepositoriesView) part; + view.showResource(selectedResource); + + } + + public void selectionChanged(IAction action, ISelection selection) { + try { + selectedResource = (IResource) ((IStructuredSelection) selection) + .getFirstElement(); + } catch (Exception e) { + Activator.getDefault().getLog().log( + new Status(IStatus.ERROR, Activator.getPluginId(), e + .getMessage(), e)); + } + action.setEnabled(selectedResource != null); + } + +} 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 62cc4c69e7..3fd8746c92 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 @@ -24,6 +24,7 @@ import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIIcons; import org.eclipse.egit.ui.UIText; import org.eclipse.egit.ui.internal.components.RepositorySelectionPage; +import org.eclipse.egit.ui.internal.repository.RepositoriesView; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; @@ -33,7 +34,9 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.transport.URIish; import org.eclipse.osgi.util.NLS; import org.eclipse.ui.IImportWizard; +import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; /** * Import Git Repository Wizard. A front end to a git clone operation. @@ -138,6 +141,15 @@ public class GitCloneWizard extends Wizard implements IImportWizard { 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); importProject.setGitDir(op.getGitDir()); @@ -149,6 +161,10 @@ public class GitCloneWizard extends Wizard implements IImportWizard { try { op.run(monitor); cloneSource.saveUriInPrefs(uri.toString()); + RepositoriesView.addDir(op.getGitDir()); + if (view != null) + view.scheduleRefresh(); + return Status.OK_STATUS; } catch (InterruptedException e) { return Status.CANCEL_STATUS; @@ -175,6 +191,9 @@ public class GitCloneWizard extends Wizard implements IImportWizard { } }); cloneSource.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/components/RefSpecPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RefSpecPage.java index c05d93c33a..0447e09527 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RefSpecPage.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RefSpecPage.java @@ -67,12 +67,7 @@ public class RefSpecPage extends BaseWizardPage { private String transportError; - // special mode for configuration: the remote name is set by the wizard - private final String remoteName; - - // hack: if there were specs when opening this page, then - // we allow to finish even if the specs table is empty - private int initialSpecSize = -1; + private String configName; /** * Create specifications selection page for provided context. @@ -85,13 +80,10 @@ public class RefSpecPage extends BaseWizardPage { * @param repoPage * repository selection page - must be predecessor of this page * in wizard. - * @param remoteName - * preselected remote name, may be null */ public RefSpecPage(final Repository local, final boolean pushPage, - final RepositorySelectionPage repoPage, String remoteName) { + final RepositorySelectionPage repoPage) { super(RefSpecPage.class.getName()); - this.remoteName = remoteName; this.local = local; this.repoPage = repoPage; this.pushPage = pushPage; @@ -113,23 +105,6 @@ public class RefSpecPage extends BaseWizardPage { }); } - /** - * Create specifications selection page for provided context. - * - * @param local - * local repository. - * @param pushPage - * true if this page is used for push specifications selection, - * false if it used for fetch specifications selection. - * @param repoPage - * repository selection page - must be predecessor of this page - * in wizard. - */ - public RefSpecPage(final Repository local, final boolean pushPage, - final RepositorySelectionPage repoPage) { - this(local, pushPage, repoPage, null); - } - public void createControl(Composite parent) { final Composite panel = new Composite(parent, SWT.NULL); panel.setLayout(new GridLayout()); @@ -186,6 +161,15 @@ public class RefSpecPage extends BaseWizardPage { super.setVisible(visible); } + /** + * Special mode: the configuration is determined by the wizard + * + * @param configName + */ + public void setConfigName(String configName) { + this.configName = configName; + } + /** * @return ref specifications as selected by user. Returned collection is a * copy, so it may be modified by caller. @@ -280,12 +264,11 @@ public class RefSpecPage extends BaseWizardPage { this.validatedRepoSelection = newRepoSelection; final String actRemoteName; - if (remoteName == null) + if (configName == null) actRemoteName = validatedRepoSelection.getConfigName(); else - actRemoteName = remoteName; - if (initialSpecSize < 0) - initialSpecSize = listRemotesOp.getRemoteRefs().size(); + actRemoteName = configName; + specsPanel.setAssistanceData(local, listRemotesOp.getRemoteRefs(), actRemoteName); @@ -298,7 +281,7 @@ public class RefSpecPage extends BaseWizardPage { if (newRepoSelection.isConfigSelected()) { saveButton.setVisible(true); saveButton.setText(NLS.bind(UIText.RefSpecPage_saveSpecifications, - remoteName)); + actRemoteName)); saveButton.getParent().layout(); final TagOpt tagOpt = newRepoSelection.getConfig().getTagOpt(); switch (tagOpt) { @@ -336,6 +319,6 @@ public class RefSpecPage extends BaseWizardPage { return; } setErrorMessage(specsPanel.getErrorMessage()); - setPageComplete(initialSpecSize > 0 || (!specsPanel.isEmpty() && specsPanel.isValid())); + setPageComplete(!specsPanel.isEmpty() && specsPanel.isValid()); } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java index 6f2233d580..71f52a98eb 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/RepositorySelectionPage.java @@ -17,13 +17,10 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.StringTokenizer; -import java.util.TreeSet; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.egit.ui.Activator; @@ -106,6 +103,8 @@ public class RepositorySelectionPage extends BaseWizardPage { private final List configuredRemotes; + private final boolean sourceSelection; + private Group authGroup; private Text uriText; @@ -162,8 +161,33 @@ public class RepositorySelectionPage extends BaseWizardPage { */ public RepositorySelectionPage(final boolean sourceSelection, final List configuredRemotes) { + this(sourceSelection, configuredRemotes, null); + } + + /** + * Special case: the URI is set externally + * + * @param sourceSelection + * true if dialog is used for source selection; false otherwise + * (destination selection). This indicates appropriate text + * messages. + * @param configuredRemotes + * list of configured remotes that user may select as an + * alternative to manual URI specification. Remotes appear in + * given order in GUI, with + * {@value Constants#DEFAULT_REMOTE_NAME} as the default choice. + * List may be null or empty - no remotes configurations appear + * in this case. Note that the provided list may be changed by + * this constructor. + * @param presetUri + * the pre-set URI + */ + public RepositorySelectionPage(final boolean sourceSelection, + final List configuredRemotes, String presetUri) { super(RepositorySelectionPage.class.getName()); this.uri = new URIish(); + this.sourceSelection = sourceSelection; + this.presetUri = presetUri; if (configuredRemotes != null) removeUnusableRemoteConfigs(configuredRemotes); @@ -194,18 +218,9 @@ public class RepositorySelectionPage extends BaseWizardPage { * messages. */ public RepositorySelectionPage(final boolean sourceSelection) { - this(sourceSelection, null); + this(sourceSelection, null, null); } - /** - * Special mode: the URI is preset by the wizard - * - * @param presetUri remote URI - */ - public RepositorySelectionPage(String presetUri) { - this(true, null); - this.presetUri = presetUri; - } /** * @return repository selection representing current page state. @@ -573,11 +588,19 @@ public class RepositorySelectionPage extends BaseWizardPage { return configuredRemotes.get(0); } - private static String getTextForRemoteConfig(final RemoteConfig rc) { + private String getTextForRemoteConfig(final RemoteConfig rc) { final StringBuilder sb = new StringBuilder(rc.getName()); sb.append(": "); //$NON-NLS-1$ boolean first = true; - for (final URIish u : rc.getURIs()) { + List uris; + if (sourceSelection) { + uris = rc.getURIs(); + } else { + // TODO shouldn't this be getPushURIs? + uris = rc.getPushURIs(); + } + + for (final URIish u : uris) { final String uString = u.toString(); if (first) first = false; @@ -753,31 +776,32 @@ public class RepositorySelectionPage extends BaseWizardPage { */ public void saveUriInPrefs(String stringToAdd) { - Set uriStrings = getUrisFromPrefs(); + List uriStrings = getUrisFromPrefs(); - if (uriStrings.add(stringToAdd)) { + if (uriStrings.indexOf(stringToAdd) == 0) + return; + uriStrings.add(0, stringToAdd); - IEclipsePreferences prefs = new InstanceScope().getNode(Activator - .getPluginId()); + IEclipsePreferences prefs = new InstanceScope().getNode(Activator + .getPluginId()); - StringBuilder sb = new StringBuilder(); - StringBuilder lb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); + StringBuilder lb = new StringBuilder(); - // there is no "good" separator for URIish, so we - // keep track of the URI lengths separately - for (String uriString : uriStrings) { - sb.append(uriString); - lb.append(uriString.length()); - lb.append(" "); //$NON-NLS-1$ - } - prefs.put(USED_URIS_PREF, sb.toString()); - prefs.put(USED_URIS_LENGTH_PREF, lb.toString()); + // there is no "good" separator for URIish, so we + // keep track of the URI lengths separately + for (String uriString : uriStrings) { + sb.append(uriString); + lb.append(uriString.length()); + lb.append(" "); //$NON-NLS-1$ + } + prefs.put(USED_URIS_PREF, sb.toString()); + prefs.put(USED_URIS_LENGTH_PREF, lb.toString()); - try { - prefs.flush(); - } catch (BackingStoreException e) { - // we simply ignore this here - } + try { + prefs.flush(); + } catch (BackingStoreException e) { + // we simply ignore this here } } @@ -786,10 +810,10 @@ public class RepositorySelectionPage extends BaseWizardPage { * * @return a (possibly empty) list of URIs, never null */ - public Set getUrisFromPrefs() { + public List getUrisFromPrefs() { // use a TreeSet to get the same sorting always - Set uriStrings = new TreeSet(); + List uriStrings = new ArrayList(); IEclipsePreferences prefs = new InstanceScope().getNode(Activator .getPluginId()); @@ -821,12 +845,9 @@ public class RepositorySelectionPage extends BaseWizardPage { ControlDecoration dec = new ControlDecoration(uriTextField, SWT.TOP | SWT.LEFT); - if (Platform.isRunning()) { - dec.setImage(FieldDecorationRegistry.getDefault() - .getFieldDecoration( - FieldDecorationRegistry.DEC_CONTENT_PROPOSAL) - .getImage()); - } + dec.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration( + FieldDecorationRegistry.DEC_CONTENT_PROPOSAL).getImage()); + dec.setShowOnlyOnFocus(true); dec.setShowHover(true); @@ -835,11 +856,15 @@ public class RepositorySelectionPage extends BaseWizardPage { IContentProposalProvider cp = new IContentProposalProvider() { public IContentProposal[] getProposals(String contents, int position) { + List resultList = new ArrayList(); + String patternString = contents; + while (patternString.length() > 0 && patternString.charAt(0)==' ') + patternString = patternString.substring(1); // make the simplest possible pattern check: allow "*" // for multiple characters - String patternString = contents.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$ + patternString = patternString.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$ // make sure we add a (logical) * at the end if (!patternString.endsWith(".*")) { //$NON-NLS-1$ patternString = patternString + ".*"; //$NON-NLS-1$ @@ -853,7 +878,7 @@ public class RepositorySelectionPage extends BaseWizardPage { pattern = null; } - Set uriStrings = getUrisFromPrefs(); + List uriStrings = getUrisFromPrefs(); for (final String uriString : uriStrings) { if (pattern!=null && !pattern.matcher(uriString).matches()) diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java index 8162eb0734..92e4652675 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java @@ -16,6 +16,7 @@ import java.net.URISyntaxException; import org.eclipse.egit.ui.UIText; import org.eclipse.egit.ui.internal.components.RefSpecPage; import org.eclipse.egit.ui.internal.components.RepositorySelectionPage; +import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.Wizard; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryConfig; @@ -24,11 +25,31 @@ import org.eclipse.osgi.util.NLS; /** * Used for "remote" configuration of a Repository + * + * If this is in "create"-mode, there will be the following pages: + *
    + *
  1. Selection of a remote name
  2. + *
  3. Fetch URL
  4. + *
  5. Fetch Specification
  6. + *
  7. Push URL
  8. + *
  9. Push Specification
  10. + *
+ *

+ * In "edit"-mode, there will be the following pages: + * + * + *

    + *
  1. Fetch or Push URL
  2. + *
  3. Fetch or Push Specification
  4. + *
+ * */ class ConfigureRemoteWizard extends Wizard { final RepositoryConfig myConfiguration; + final boolean createMode; + final boolean pushMode; final String myRemoteName; @@ -40,6 +61,65 @@ class ConfigureRemoteWizard extends Wizard { this(repository, null, false); } + @Override + public IWizardPage getNextPage(IWizardPage page) { + + + if (!createMode) { + return super.getNextPage(page); + } + if (page instanceof SelectRemoteNamePage) { + SelectRemoteNamePage srp = (SelectRemoteNamePage) page; + if (srp.configureFetch.getSelection()) { + return getPages()[1]; + } + if (srp.configurePush.getSelection()) { + return getPages()[3]; + } + } + if (page == getPages()[1] || page == getPages()[3]) { + RefSpecPage next = (RefSpecPage) getPages()[2]; + next + .setConfigName(((SelectRemoteNamePage) getPages()[0]).remoteName + .getText()); + next = (RefSpecPage) getPages()[4]; + next + .setConfigName(((SelectRemoteNamePage) getPages()[0]).remoteName + .getText()); + + } + if (page == getPages()[2]) { + SelectRemoteNamePage srp = (SelectRemoteNamePage) getPages()[0]; + if (srp.configurePush.getSelection()) { + return getPages()[3]; + } else { + return null; + } + } + + return super.getNextPage(page); + } + + @Override + public boolean canFinish() { + if (createMode) { + IWizardPage[] pages = getPages(); + if (pages[0].isPageComplete()) { + boolean done = true; + SelectRemoteNamePage srp = (SelectRemoteNamePage) pages[0]; + if (srp.configureFetch.getSelection()) + done = done & pages[1].isPageComplete() + & pages[2].isPageComplete(); + if (srp.configurePush.getSelection()) + done = done & pages[3].isPageComplete() + & pages[4].isPageComplete(); + return done; + } + return false; + } + return super.canFinish(); + } + /** * * @param repository @@ -51,22 +131,51 @@ class ConfigureRemoteWizard extends Wizard { myConfiguration = repository.getConfig(); myRemoteName = remoteName; pushMode = push; - if (myRemoteName == null) { - // create mode: add remote name page and repository selection page + createMode = remoteName == null; + if (createMode) { + // selection of a remote name addPage(new SelectRemoteNamePage()); - addPage(new RepositorySelectionPage(null)); + + // repository selection for fetch + RepositorySelectionPage sp = new RepositorySelectionPage(false, + null, myConfiguration.getString(RepositoriesView.REMOTE, + null, RepositoriesView.URL)); + addPage(sp); + + // ref spec for fetch + RefSpecPage rsp = new RefSpecPage(repository, false, sp); + addPage(rsp); + + // repository selection for push + sp = new RepositorySelectionPage(true, null, myConfiguration + .getString(RepositoriesView.REMOTE, null, + RepositoriesView.PUSHURL)); + addPage(sp); + + // ref spec for push + rsp = new RefSpecPage(repository, true, sp); + addPage(rsp); + setWindowTitle(UIText.ConfigureRemoteWizard_WizardTitle_New); + } else { // edit mode: no remote name page and pre-selected repository // selection page - RepositorySelectionPage sp = new RepositorySelectionPage( - myConfiguration.getString(RepositoriesView.REMOTE, - myRemoteName, RepositoriesView.URL)); + RepositorySelectionPage sp; + if (pushMode) { + sp = new RepositorySelectionPage(pushMode, null, + myConfiguration.getString(RepositoriesView.REMOTE, + myRemoteName, RepositoriesView.PUSHURL)); + } else { + sp = new RepositorySelectionPage(pushMode, null, + myConfiguration.getString(RepositoriesView.REMOTE, + myRemoteName, RepositoriesView.URL)); + } addPage(sp); // and also the corresponding configuration page - RefSpecPage rsp = new RefSpecPage(repository, pushMode, sp, - myRemoteName); + RefSpecPage rsp = new RefSpecPage(repository, pushMode, sp); + rsp.setConfigName(myRemoteName); addPage(rsp); setWindowTitle(NLS.bind( UIText.ConfigureRemoteWizard_WizardTitle_Change, @@ -86,48 +195,71 @@ class ConfigureRemoteWizard extends Wizard { @Override public boolean performFinish() { - String actRemoteName = myRemoteName; - if (myRemoteName == null) { - SelectRemoteNamePage page = (SelectRemoteNamePage) getPage(SelectRemoteNamePage.class + RemoteConfig config; + if (createMode) { + + SelectRemoteNamePage srp = (SelectRemoteNamePage) getPage(SelectRemoteNamePage.class .getName()); - actRemoteName = page.remoteName.getText(); - } - RepositorySelectionPage sp = (RepositorySelectionPage) getPage(RepositorySelectionPage.class - .getName()); + String actRemoteName = srp.remoteName.getText(); + + try { + config = new RemoteConfig(myConfiguration, actRemoteName); + } catch (URISyntaxException e1) { + // TODO better Exception handling + return false; + } + + if (srp.configureFetch.getSelection()) { + RepositorySelectionPage sp = (RepositorySelectionPage) getPages()[1]; + config.addURI(sp.getSelection().getURI()); + RefSpecPage specPage = (RefSpecPage) getPages()[2]; + config.setFetchRefSpecs(specPage.getRefSpecs()); + config.setTagOpt(specPage.getTagOpt()); + config.update(myConfiguration); + sp.saveUriInPrefs(sp.getSelection().getURI().toString()); - String uriString = sp.getSelection().getURI().toString(); + } + if (srp.configurePush.getSelection()) { + RepositorySelectionPage sp = (RepositorySelectionPage) getPages()[3]; + config.addPushURI(sp.getSelection().getURI()); + RefSpecPage specPage = (RefSpecPage) getPages()[4]; + config.setPushRefSpecs(specPage.getRefSpecs()); + config.update(myConfiguration); + sp.saveUriInPrefs(sp.getSelection().getURI().toString()); + } - myConfiguration.setString(RepositoriesView.REMOTE, actRemoteName, - RepositoriesView.URL, uriString); + } else { - if (myRemoteName != null) { + RepositorySelectionPage sp = (RepositorySelectionPage) getPage(RepositorySelectionPage.class + .getName()); RefSpecPage specPage = (RefSpecPage) getPage(RefSpecPage.class .getName()); - if (specPage.getRefSpecs().isEmpty()) { - specPage.setVisible(true); - specPage.setVisible(false); - } - - RemoteConfig config; try { - config = new RemoteConfig(myConfiguration, actRemoteName); + config = new RemoteConfig(myConfiguration, myRemoteName); } catch (URISyntaxException e1) { // TODO better Exception handling return false; } - if (pushMode) + + if (pushMode){ + config.addPushURI(sp.getSelection().getURI()); config.setPushRefSpecs(specPage.getRefSpecs()); + } else { + config.addURI(sp.getSelection().getURI()); config.setFetchRefSpecs(specPage.getRefSpecs()); config.setTagOpt(specPage.getTagOpt()); } - config.update(myConfiguration); + + sp.saveUriInPrefs(sp.getSelection().getURI().toString()); } + config.update(myConfiguration); + try { myConfiguration.save(); return true; 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 0b754dadea..d64163679e 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 @@ -15,19 +15,22 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -40,59 +43,54 @@ import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.egit.core.op.BranchOperation; import org.eclipse.egit.core.op.ConnectProviderOperation; +import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIIcons; +import org.eclipse.egit.ui.UIText; import org.eclipse.egit.ui.internal.clone.GitCloneWizard; -import org.eclipse.egit.ui.internal.clone.GitProjectsImportPage; import org.eclipse.egit.ui.internal.repository.RepositoryTreeNode.RepositoryTreeNodeType; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; -import org.eclipse.jface.resource.CompositeImageDescriptor; -import org.eclipse.jface.viewers.BaseLabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.Wizard; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.lib.RepositoryCache; import org.eclipse.jgit.lib.RepositoryConfig; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseTrackAdapter; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.ISelectionService; import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.ide.FileStoreEditorInput; +import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.IWorkbenchSiteProgressService; -import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.ui.views.properties.PropertySheet; import org.eclipse.ui.views.properties.PropertySheetPage; @@ -107,25 +105,33 @@ import org.osgi.service.prefs.BackingStoreException; * a Git Repository. This list is stored in some Preferences object and used to * build the tree in the view. *

+ * Implements {@link ISelectionProvider} in order to integrate with the + * Properties view. + *

* TODO - *

  • Icons
  • - *
  • String externalization
  • *
  • Clarification whether to show projects, perhaps configurable switch
  • * */ public class RepositoriesView extends ViewPart implements ISelectionProvider { + /** The view ID */ + public static final String VIEW_ID = "org.eclipse.egit.ui.RepositoriesView"; //$NON-NLS-1$ + // TODO central constants? RemoteConfig ones are private static final String REMOTE = "remote"; //$NON-NLS-1$ static final String URL = "url"; //$NON-NLS-1$ + static final String PUSHURL = "pushurl"; //$NON-NLS-1$ + static final String FETCH = "fetch"; //$NON-NLS-1$ static final String PUSH = "push"; //$NON-NLS-1$ private static final String PREFS_DIRECTORIES = "GitRepositoriesView.GitDirectories"; //$NON-NLS-1$ + private static final String PREFS_SYNCED = "GitRepositoriesView.SyncWithSelection"; //$NON-NLS-1$ + private final List selectionListeners = new ArrayList(); private ISelection currentSelection = new StructuredSelection(); @@ -140,415 +146,11 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { private IAction refreshAction; - private static final class ContentProvider implements ITreeContentProvider { - - @SuppressWarnings("unchecked") - public Object[] getElements(Object inputElement) { - - Comparator> sorter = new Comparator>() { - - public int compare(RepositoryTreeNode o1, - RepositoryTreeNode o2) { - return getRepositoryName(o1.getObject()).compareTo( - getRepositoryName(o2.getObject())); - } - - }; - - Set> output = new TreeSet>( - sorter); - - for (Repository repo : ((List) inputElement)) { - output.add(new RepositoryTreeNode(null, - RepositoryTreeNodeType.REPO, repo, repo)); - } - - return output.toArray(); - } - - public void dispose() { - // nothing - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // nothing - } - - public Object[] getChildren(Object parentElement) { - - RepositoryTreeNode node = (RepositoryTreeNode) parentElement; - Repository repo = node.getRepository(); - - switch (node.getType()) { - - case BRANCHES: - - List> refs = new ArrayList>(); - - for (Ref ref : repo.getAllRefs().values()) { - refs.add(new RepositoryTreeNode(node, - RepositoryTreeNodeType.REF, repo, ref)); - } - - return refs.toArray(); - - case REMOTES: - - List> remotes = new ArrayList>(); - - Repository rep = node.getRepository(); - - Set configNames = rep.getConfig() - .getSubsections(REMOTE); - - for (String configName : configNames) { - remotes.add(new RepositoryTreeNode(node, - RepositoryTreeNodeType.REMOTE, repo, configName)); - } - - return remotes.toArray(); - - case REPO: - - List> branches = new ArrayList>(); - - branches.add(new RepositoryTreeNode(node, - RepositoryTreeNodeType.BRANCHES, node.getRepository(), - node.getRepository())); - - branches.add(new RepositoryTreeNode(node, - RepositoryTreeNodeType.PROJECTS, node.getRepository(), - node.getRepository())); - - branches.add(new RepositoryTreeNode(node, - RepositoryTreeNodeType.REMOTES, node.getRepository(), - node.getRepository())); - - return branches.toArray(); - - case PROJECTS: - - List> projects = new ArrayList>(); - - // TODO do we want to show the projects here? - Collection result = new HashSet(); - Set traversed = new HashSet(); - collectProjectFilesFromDirectory(result, repo.getDirectory() - .getParentFile(), traversed, new NullProgressMonitor()); - for (File file : result) { - projects.add(new RepositoryTreeNode(node, - RepositoryTreeNodeType.PROJ, repo, file)); - } - - Comparator> sorter = new Comparator>() { - - public int compare(RepositoryTreeNode o1, - RepositoryTreeNode o2) { - return o1.getObject().getName().compareTo( - o2.getObject().getName()); - } - }; - Collections.sort(projects, sorter); - - return projects.toArray(); - - default: - return null; - } - - } - - public Object getParent(Object element) { - - return ((RepositoryTreeNode) element).getParent(); - } - - public boolean hasChildren(Object element) { - Object[] children = getChildren(element); - return children != null && children.length > 0; - } - - private boolean collectProjectFilesFromDirectory( - Collection files, File directory, - Set directoriesVisited, IProgressMonitor monitor) { - - // stolen from the GitCloneWizard; perhaps we should completely drop - // the projects from this view, though - if (monitor.isCanceled()) { - return false; - } - monitor.subTask(NLS.bind( - RepositoryViewUITexts.RepositoriesView_Checking_Message, - directory.getPath())); - File[] contents = directory.listFiles(); - if (contents == null) - return false; - - // first look for project description files - final String dotProject = IProjectDescription.DESCRIPTION_FILE_NAME; - for (int i = 0; i < contents.length; i++) { - File file = contents[i]; - if (file.isFile() && file.getName().equals(dotProject)) { - files.add(file.getParentFile()); - // don't search sub-directories since we can't have nested - // projects - return true; - } - } - // no project description found, so recurse into sub-directories - for (int i = 0; i < contents.length; i++) { - if (contents[i].isDirectory()) { - if (!contents[i].getName().equals( - GitProjectsImportPage.METADATA_FOLDER)) { - try { - String canonicalPath = contents[i] - .getCanonicalPath(); - if (!directoriesVisited.add(canonicalPath)) { - // already been here --> do not recurse - continue; - } - } catch (IOException exception) { - StatusManager.getManager().handle( - new Status(IStatus.ERROR, Activator - .getPluginId(), exception - .getLocalizedMessage(), exception)); - - } - collectProjectFilesFromDirectory(files, contents[i], - directoriesVisited, monitor); - } - } - } - return true; - } + private IAction linkWithSelectionAction; - } - - private static final class LabelProvider extends BaseLabelProvider - implements ITableLabelProvider { - - // private DefaultInformationControl infoControl; - - /** - * - * @param viewer - */ - LabelProvider(final TreeViewer viewer) { - - viewer.setLabelProvider(this); - Tree tree = viewer.getTree(); - TreeColumn col = new TreeColumn(tree, SWT.NONE); - col.setWidth(400); - viewer.getTree().addMouseTrackListener(new MouseTrackAdapter() { - - @Override - public void mouseHover(MouseEvent e) { - - // Point eventPoint = new Point(e.x, e.y); - // - // TreeItem item = viewer.getTree().getItem(eventPoint); - // if (item != null) { - // - // RepositoryTreeNode node = (RepositoryTreeNode) item - // .getData(); - // String text = node.getRepository().getDirectory() - // .getAbsolutePath(); - // - // final ViewerCell cell = viewer.getCell(eventPoint); - // - // if (infoControl != null && infoControl.isVisible()) { - // infoControl.setVisible(false); - // } - // - // GC testGc = new GC(cell.getControl()); - // final Point textExtent = testGc.textExtent(text); - // testGc.dispose(); - // - // if (infoControl == null || !infoControl.isVisible()) { - // - // IInformationPresenter ips = new IInformationPresenter() { - // - // public String updatePresentation( - // Display display, String hoverInfo, - // TextPresentation presentation, - // int maxWidth, int maxHeight) { - // return hoverInfo; - // } - // - // }; - // - // infoControl = new DefaultInformationControl(Display - // .getCurrent().getActiveShell().getShell(), - // ips) { - // - // @Override - // public void setInformation(String content) { - // super.setInformation(content); - // super.setSize(textExtent.x, textExtent.y); - // } - // - // }; - // } - // - // Point dispPoint = viewer.getControl().toDisplay( - // eventPoint); - // - // infoControl.setLocation(dispPoint); - // - // // the default info provider works better with \r ... - // infoControl.setInformation(text); - // - // final MouseMoveListener moveListener = new - // MouseMoveListener() { - // - // public void mouseMove(MouseEvent evt) { - // infoControl.setVisible(false); - // cell.getControl().removeMouseMoveListener(this); - // - // } - // }; - // - // cell.getControl().addMouseMoveListener(moveListener); - // - // infoControl.setVisible(true); - // - // } - - } - - }); - - } - - public Image getColumnImage(Object element, int columnIndex) { - return decorateImage(((RepositoryTreeNode) element).getType() - .getIcon(), element); - } - - public String getColumnText(Object element, int columnIndex) { - - RepositoryTreeNode node = (RepositoryTreeNode) element; - switch (node.getType()) { - case REPO: - File directory = ((Repository) node.getObject()).getDirectory() - .getParentFile(); - return (directory.getName() + " - " + directory //$NON-NLS-1$ - .getAbsolutePath()); - case BRANCHES: - return RepositoryViewUITexts.RepositoriesView_Branches_Nodetext; - case REMOTES: - return RepositoryViewUITexts.RepositoriesView_RemotesNodeText; - case REMOTE: - String name = (String) node.getObject(); - String url = node.getRepository().getConfig().getString(REMOTE, - name, URL); - if (url != null && !url.equals("")) //$NON-NLS-1$ - name = name + " - " + url; //$NON-NLS-1$ - return name; - case PROJECTS: - return RepositoryViewUITexts.RepositoriesView_ExistingProjects_Nodetext; - case REF: - Ref ref = (Ref) node.getObject(); - // shorten the name - String refName = node.getRepository().shortenRefName( - ref.getName()); - if (ref.isSymbolic()) { - refName = refName - + " - " //$NON-NLS-1$ - + node.getRepository().shortenRefName( - ref.getLeaf().getName()); - } - return refName; - case PROJ: - - File file = (File) node.getObject(); - return file.getName(); - - default: - return null; - } - } - - public Image decorateImage(final Image image, Object element) { - - RepositoryTreeNode node = (RepositoryTreeNode) element; - switch (node.getType()) { - - case REF: - Ref ref = (Ref) node.getObject(); - // shorten the name - String refName = node.getRepository().shortenRefName( - ref.getName()); - try { - String branch = node.getBranch(); - if (refName.equals(branch)) { - CompositeImageDescriptor cd = new CompositeImageDescriptor() { - - @Override - protected Point getSize() { - return new Point(image.getBounds().width, image - .getBounds().width); - } - - @Override - protected void drawCompositeImage(int width, - int height) { - drawImage(image.getImageData(), 0, 0); - drawImage( - UIIcons.OVR_CHECKEDOUT.getImageData(), - 0, 0); - - } - }; - return cd.createImage(); - } - } catch (IOException e1) { - // simply ignore here - } - return image; - - case PROJ: - - File file = (File) node.getObject(); - - for (IProject proj : ResourcesPlugin.getWorkspace().getRoot() - .getProjects()) { - if (proj.getLocation().equals( - new Path(file.getAbsolutePath()))) { - CompositeImageDescriptor cd = new CompositeImageDescriptor() { - - @Override - protected Point getSize() { - return new Point(image.getBounds().width, image - .getBounds().width); - } - - @Override - protected void drawCompositeImage(int width, - int height) { - drawImage(image.getImageData(), 0, 0); - drawImage( - UIIcons.OVR_CHECKEDOUT.getImageData(), - 0, 0); - - } - }; - return cd.createImage(); - } - } - return image; - - default: - return image; - } - } - - } - - private List getGitDirs() { + private static List getDirs() { List resultStrings = new ArrayList(); - String dirs = new InstanceScope().getNode(Activator.getPluginId()).get( - PREFS_DIRECTORIES, ""); //$NON-NLS-1$ + String dirs = getPrefs().get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$ if (dirs != null && dirs.length() > 0) { StringTokenizer tok = new StringTokenizer(dirs, File.pathSeparator); while (tok.hasMoreTokens()) { @@ -563,10 +165,16 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { return resultStrings; } - private void removeDir(String dir) { + private static void removeDir(File file) { + + String dir; + try { + dir = file.getCanonicalPath(); + } catch (IOException e1) { + dir = file.getAbsolutePath(); + } - IEclipsePreferences prefs = new InstanceScope().getNode(Activator - .getPluginId()); + IEclipsePreferences prefs = getPrefs(); TreeSet resultStrings = new TreeSet(); String dirs = prefs.get(PREFS_DIRECTORIES, ""); //$NON-NLS-1$ @@ -576,7 +184,11 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { String dirName = tok.nextToken(); File testFile = new File(dirName); if (testFile.exists()) { - resultStrings.add(dirName); + try { + resultStrings.add(testFile.getCanonicalPath()); + } catch (IOException e) { + resultStrings.add(testFile.getAbsolutePath()); + } } } } @@ -602,7 +214,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { @Override public Object getAdapter(Class adapter) { - + // integrate with Properties view if (adapter == IPropertySheetPage.class) { PropertySheetPage page = new PropertySheetPage(); page @@ -623,8 +235,9 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { main.setLayout(new GridLayout(1, false)); tv = new TreeViewer(main); - tv.setContentProvider(new ContentProvider()); - new LabelProvider(tv); + tv.setContentProvider(new RepositoriesViewContentProvider()); + // the label provider registers itself + new RepositoriesViewLabelProvider(tv); getSite().setSelectionProvider(this); @@ -642,6 +255,8 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { } }); + // make the tree rather wide to accommodate long directory names + tv.getTree().getColumn(0).setWidth(700); GridDataFactory.fillDefaults().grab(true, true).applyTo(tv.getTree()); @@ -650,6 +265,39 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { addActionsToToolbar(); scheduleRefresh(); + + ISelectionService srv = (ISelectionService) getSite().getService( + ISelectionService.class); + srv.addPostSelectionListener(new ISelectionListener() { + + public void selectionChanged(IWorkbenchPart part, + ISelection selection) { + + if (linkWithSelectionAction == null + || !linkWithSelectionAction.isChecked()) + return; + + reactOnSelection(selection); + } + + }); + } + + private void reactOnSelection(ISelection selection) { + if (selection instanceof StructuredSelection) { + StructuredSelection ssel = (StructuredSelection) selection; + if (ssel.size() != 1) + return; + if (ssel.getFirstElement() instanceof IResource) { + showResource((IResource) ssel.getFirstElement()); + } + if (ssel.getFirstElement() instanceof IAdaptable) { + IResource adapted = (IResource) ((IAdaptable) ssel + .getFirstElement()).getAdapter(IResource.class); + if (adapted != null) + showResource(adapted); + } + } } private void addContextMenu() { @@ -676,8 +324,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { private void addMenuItemsForPanel(Menu men) { MenuItem importItem = new MenuItem(men, SWT.PUSH); - importItem - .setText(RepositoryViewUITexts.RepositoriesView_ImportRepository_MenuItem); + importItem.setText(UIText.RepositoriesView_ImportRepository_MenuItem); importItem.addSelectionListener(new SelectionAdapter() { @Override @@ -688,8 +335,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { }); MenuItem addItem = new MenuItem(men, SWT.PUSH); - addItem - .setText(RepositoryViewUITexts.RepositoriesView_AddRepository_MenuItem); + addItem.setText(UIText.RepositoriesView_AddRepository_MenuItem); addItem.addSelectionListener(new SelectionAdapter() { @Override @@ -729,8 +375,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { if (importableProjectsOnly) { MenuItem sync = new MenuItem(men, SWT.PUSH); - sync - .setText(RepositoryViewUITexts.RepositoriesView_ImportProject_MenuItem); + sync.setText(UIText.RepositoriesView_ImportProject_MenuItem); sync.addSelectionListener(new SelectionAdapter() { @@ -805,8 +450,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { final Ref ref = (Ref) node.getObject(); MenuItem checkout = new MenuItem(men, SWT.PUSH); - checkout - .setText(RepositoryViewUITexts.RepositoriesView_CheckOut_MenuItem); + checkout.setText(UIText.RepositoriesView_CheckOut_MenuItem); checkout.addSelectionListener(new SelectionAdapter() { @Override @@ -829,11 +473,9 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { new NullProgressMonitor()); scheduleRefresh(); } catch (CoreException e1) { - MessageDialog - .openError( - getSite().getShell(), - RepositoryViewUITexts.RepositoriesView_Error_WindowTitle, - e1.getMessage()); + MessageDialog.openError(getSite().getShell(), + UIText.RepositoriesView_Error_WindowTitle, e1 + .getMessage()); } } @@ -847,113 +489,10 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { final Repository repo = (Repository) node.getObject(); - MenuItem importProjects = new MenuItem(men, SWT.PUSH); - importProjects - .setText(RepositoryViewUITexts.RepositoriesView_ImportExistingProjects_MenuItem); - importProjects.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetSelected(SelectionEvent e) { - Wizard wiz = new ExternalProjectImportWizard(repo - .getWorkDir().getAbsolutePath()) { - - @Override - public void addPages() { - super.addPages(); - // we could add some page with a single - } - - @Override - public boolean performFinish() { - - final Set previousLocations = new HashSet(); - // we want to share only new projects - for (IProject project : ResourcesPlugin - .getWorkspace().getRoot().getProjects()) { - previousLocations.add(project.getLocation()); - } - - boolean success = super.performFinish(); - if (success) { - // IWizardPage page = getPage("Share"); - // TODO evaluate checkbox or such, but - // if we do share - // always, we don't even need another - // page - - IWorkspaceRunnable wsr = new IWorkspaceRunnable() { - - public void run(IProgressMonitor monitor) - throws CoreException { - File gitDir = repo.getDirectory(); - File gitWorkDir = repo.getWorkDir(); - Path workPath = new Path(gitWorkDir - .getAbsolutePath()); - - // we check which projects are - // in the workspace - // pointing to a location in the - // repo's - // working directory - // and share them - for (IProject prj : ResourcesPlugin - .getWorkspace().getRoot() - .getProjects()) { - - if (workPath.isPrefixOf(prj - .getLocation())) { - if (previousLocations - .contains(prj - .getLocation())) { - continue; - } - ConnectProviderOperation connectProviderOperation = new ConnectProviderOperation( - prj, gitDir); - connectProviderOperation - .run(new SubProgressMonitor( - monitor, 20)); - - } - } - - } - }; - - try { - ResourcesPlugin.getWorkspace().run( - wsr, - ResourcesPlugin.getWorkspace() - .getRoot(), - IWorkspace.AVOID_UPDATE, - new NullProgressMonitor()); - scheduleRefresh(); - } catch (CoreException ce) { - MessageDialog - .openError( - getShell(), - RepositoryViewUITexts.RepositoriesView_Error_WindowTitle, - ce.getMessage()); - } - - } - return success; - } - - }; - - WizardDialog dlg = new WizardDialog(getSite().getShell(), - wiz); - dlg.open(); - } - - }); - // TODO "import existing plug-in" menu item - // TODO "configure" menu item MenuItem remove = new MenuItem(men, SWT.PUSH); - remove - .setText(RepositoryViewUITexts.RepositoriesView_Remove_MenuItem); + remove.setText(UIText.RepositoriesView_Remove_MenuItem); remove.addSelectionListener(new SelectionAdapter() { @Override @@ -989,7 +528,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { } } - removeDir(repo.getDirectory().getAbsolutePath()); + removeDir(repo.getDirectory()); scheduleRefresh(); } }; @@ -1109,9 +648,10 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { // // }); + new MenuItem(men, SWT.SEPARATOR); + MenuItem openPropsView = new MenuItem(men, SWT.PUSH); - openPropsView - .setText(RepositoryViewUITexts.RepositoriesView_OpenPropertiesMenu); + openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu); openPropsView.addSelectionListener(new SelectionAdapter() { @Override @@ -1131,8 +671,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { if (node.getType() == RepositoryTreeNodeType.REMOTES) { MenuItem remoteConfig = new MenuItem(men, SWT.PUSH); - remoteConfig - .setText(RepositoryViewUITexts.RepositoriesView_NewRemoteMenu); + remoteConfig.setText(UIText.RepositoriesView_NewRemoteMenu); remoteConfig.addSelectionListener(new SelectionAdapter() { @Override @@ -1153,7 +692,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH); configureUrlFetch - .setText(RepositoryViewUITexts.RepositoriesView_ConfigureFetchMenu); + .setText(UIText.RepositoriesView_ConfigureFetchMenu); configureUrlFetch.addSelectionListener(new SelectionAdapter() { @Override @@ -1169,8 +708,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { }); MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH); - configureUrlPush - .setText(RepositoryViewUITexts.RepositoriesView_ConfigurePushMenu); + configureUrlPush.setText(UIText.RepositoriesView_ConfigurePushMenu); configureUrlPush.addSelectionListener(new SelectionAdapter() { @Override @@ -1188,8 +726,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { new MenuItem(men, SWT.SEPARATOR); MenuItem removeRemote = new MenuItem(men, SWT.PUSH); - removeRemote - .setText(RepositoryViewUITexts.RepositoriesView_RemoveRemoteMenu); + removeRemote.setText(UIText.RepositoriesView_RemoveRemoteMenu); removeRemote.addSelectionListener(new SelectionAdapter() { @Override @@ -1198,10 +735,10 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { boolean ok = MessageDialog .openConfirm( getSite().getShell(), - RepositoryViewUITexts.RepositoriesView_ConfirmDeleteRemoteHeader, + UIText.RepositoriesView_ConfirmDeleteRemoteHeader, NLS .bind( - RepositoryViewUITexts.RepositoriesView_ConfirmDeleteRemoteMessage, + UIText.RepositoriesView_ConfirmDeleteRemoteMessage, name)); if (ok) { RepositoryConfig config = node.getRepository() @@ -1211,11 +748,9 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { config.save(); scheduleRefresh(); } catch (IOException e1) { - MessageDialog - .openError( - getSite().getShell(), - RepositoryViewUITexts.RepositoriesView_ErrorHeader, - e1.getMessage()); + MessageDialog.openError(getSite().getShell(), + UIText.RepositoriesView_ErrorHeader, e1 + .getMessage()); } } @@ -1226,8 +761,7 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { new MenuItem(men, SWT.SEPARATOR); MenuItem openPropsView = new MenuItem(men, SWT.PUSH); - openPropsView - .setText(RepositoryViewUITexts.RepositoriesView_OpenPropertiesMenu); + openPropsView.setText(UIText.RepositoriesView_OpenPropertiesMenu); openPropsView.addSelectionListener(new SelectionAdapter() { @Override @@ -1243,57 +777,222 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { }); } + + if (node.getType() == RepositoryTreeNodeType.FILE) { + + final File file = (File) node.getObject(); + + MenuItem openInTextEditor = new MenuItem(men, SWT.PUSH); + openInTextEditor + .setText(UIText.RepositoriesView_OpenInTextEditor_menu); + openInTextEditor.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + IFileStore store = EFS.getLocalFileSystem().getStore( + new Path(file.getAbsolutePath())); + try { + // TODO do we need a read-only editor here? + IDE.openEditor(getSite().getPage(), + new FileStoreEditorInput(store), + EditorsUI.DEFAULT_TEXT_EDITOR_ID); + + } catch (PartInitException e1) { + MessageDialog.openError(getSite().getShell(), + UIText.RepositoriesView_Error_WindowTitle, e1 + .getMessage()); + } + + } + + }); + } + + if (node.getType() == RepositoryTreeNodeType.FOLDER) { + String path = ((File) node.getObject()).getAbsolutePath(); + createImportProjectItem(men, node.getRepository(), path); + } + + if (node.getType() == RepositoryTreeNodeType.WORKINGDIR) { + String path = node.getRepository().getWorkDir().getAbsolutePath(); + createImportProjectItem(men, node.getRepository(), path); + } + + } + + private void createImportProjectItem(Menu men, final Repository repo, + final String path) { + MenuItem importProjects; + importProjects = new MenuItem(men, SWT.PUSH); + importProjects + .setText(UIText.RepositoriesView_ImportExistingProjects_MenuItem); + importProjects.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + Wizard wiz = new ExternalProjectImportWizard(path) { + + @Override + public void addPages() { + super.addPages(); + // we could add some page with a single + } + + @Override + public boolean performFinish() { + + final Set previousLocations = new HashSet(); + // we want to share only new projects + for (IProject project : ResourcesPlugin.getWorkspace() + .getRoot().getProjects()) { + previousLocations.add(project.getLocation()); + } + + boolean success = super.performFinish(); + if (success) { + // IWizardPage page = getPage("Share"); + // TODO evaluate checkbox or such, but + // if we do share + // always, we don't even need another + // page + + IWorkspaceRunnable wsr = new IWorkspaceRunnable() { + + public void run(IProgressMonitor monitor) + throws CoreException { + File gitDir = repo.getDirectory(); + File gitWorkDir = repo.getWorkDir(); + Path workPath = new Path(gitWorkDir + .getAbsolutePath()); + + // we check which projects are + // in the workspace + // pointing to a location in the + // repo's + // working directory + // and share them + for (IProject prj : ResourcesPlugin + .getWorkspace().getRoot() + .getProjects()) { + + if (workPath.isPrefixOf(prj + .getLocation())) { + if (previousLocations.contains(prj + .getLocation())) { + continue; + } + ConnectProviderOperation connectProviderOperation = new ConnectProviderOperation( + prj, gitDir); + connectProviderOperation + .run(new SubProgressMonitor( + monitor, 20)); + + } + } + + } + }; + + try { + ResourcesPlugin.getWorkspace().run( + wsr, + ResourcesPlugin.getWorkspace() + .getRoot(), + IWorkspace.AVOID_UPDATE, + new NullProgressMonitor()); + scheduleRefresh(); + } catch (CoreException ce) { + MessageDialog + .openError( + getShell(), + UIText.RepositoriesView_Error_WindowTitle, + ce.getMessage()); + } + + } + return success; + } + + }; + + WizardDialog dlg = new WizardDialog(getSite().getShell(), wiz); + dlg.open(); + } + + }); } private void addActionsToToolbar() { - importAction = new Action( - RepositoryViewUITexts.RepositoriesView_Import_Button) { + importAction = new Action(UIText.RepositoriesView_Import_Button) { @Override public void run() { GitCloneWizard wiz = new GitCloneWizard(); wiz.init(null, null); new WizardDialog(getSite().getShell(), wiz).open(); - updateDirStrings(new NullProgressMonitor()); } }; - importAction - .setToolTipText(RepositoryViewUITexts.RepositoriesView_Clone_Tooltip); + importAction.setToolTipText(UIText.RepositoriesView_Clone_Tooltip); importAction.setImageDescriptor(UIIcons.IMPORT); getViewSite().getActionBars().getToolBarManager().add(importAction); - addAction = new Action( - RepositoryViewUITexts.RepositoriesView_Add_Button) { + addAction = new Action(UIText.RepositoriesView_Add_Button) { @Override public void run() { RepositorySearchDialog sd = new RepositorySearchDialog( - getSite().getShell(), ResourcesPlugin.getWorkspace() - .getRoot().getLocation().toOSString(), - getGitDirs()); + getSite().getShell(), getDirs()); if (sd.open() == Window.OK) { Set dirs = new HashSet(); - dirs.addAll(getGitDirs()); + dirs.addAll(getDirs()); if (dirs.addAll(sd.getDirectories())) - saveDirStrings(dirs); + saveDirs(dirs); scheduleRefresh(); } } }; - addAction - .setToolTipText(RepositoryViewUITexts.RepositoriesView_AddRepository_Tooltip); + addAction.setToolTipText(UIText.RepositoriesView_AddRepository_Tooltip); addAction.setImageDescriptor(UIIcons.NEW_REPOSITORY); getViewSite().getActionBars().getToolBarManager().add(addAction); - // TODO if we don't show projects, then we probably don't need refresh + linkWithSelectionAction = new Action(UIText.RepositoriesView_LinkWithSelection_action, + IAction.AS_CHECK_BOX) { - refreshAction = new Action( - RepositoryViewUITexts.RepositoriesView_Refresh_Button) { + @Override + public void run() { + IEclipsePreferences prefs = getPrefs(); + prefs.putBoolean(PREFS_SYNCED, isChecked()); + try { + prefs.flush(); + } catch (BackingStoreException e) { + // ignore here + } + if (isChecked()) { + ISelectionService srv = (ISelectionService) getSite() + .getService(ISelectionService.class); + reactOnSelection(srv.getSelection()); + } + + } + + }; + + linkWithSelectionAction.setToolTipText(UIText.RepositoriesView_LinkWithSelection_action); + + linkWithSelectionAction.setImageDescriptor(UIIcons.ELCL16_SYNCED); + + linkWithSelectionAction.setChecked(getPrefs().getBoolean(PREFS_SYNCED, + false)); + + getViewSite().getActionBars().getToolBarManager().add( + linkWithSelectionAction); + + refreshAction = new Action(UIText.RepositoriesView_Refresh_Button) { @Override public void run() { @@ -1306,6 +1005,13 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { getViewSite().getActionBars().getToolBarManager().add(refreshAction); } + /** + * @return the preferences + */ + protected static IEclipsePreferences getPrefs() { + return new InstanceScope().getNode(Activator.getPluginId()); + } + @Override public void dispose() { // make sure to cancel the refresh job @@ -1316,7 +1022,10 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { super.dispose(); } - private void scheduleRefresh() { + /** + * Schedules a refreh + */ + public void scheduleRefresh() { Job job = new Job("Refreshing Git Repositories view") { //$NON-NLS-1$ @@ -1378,12 +1087,12 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { private List getRepositoriesFromDirs(IProgressMonitor monitor) throws InterruptedException { - List gitDirStrings = getGitDirs(); + List gitDirStrings = getDirs(); List input = new ArrayList(); for (String dirString : gitDirStrings) { if (monitor.isCanceled()) { throw new InterruptedException( - RepositoryViewUITexts.RepositoriesView_ActionCanceled_Message); + UIText.RepositoriesView_ActionCanceled_Message); } try { File dir = new File(dirString); @@ -1399,26 +1108,41 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { return input; } - private void updateDirStrings(IProgressMonitor monitor) { + /** + * Adds a directory to the list if it is not already there + * + * @param file + * @return see {@link Collection#add(Object)} + */ + public static boolean addDir(File file) { - IPath path = ResourcesPlugin.getWorkspace().getRoot().getLocation(); - File root = path.toFile(); - TreeSet dirStrings = new TreeSet(); - recurseDir(root, dirStrings, monitor); - saveDirStrings(dirStrings); - scheduleRefresh(); + String dirString; + try { + dirString = file.getCanonicalPath(); + } catch (IOException e) { + dirString = file.getAbsolutePath(); + } + List dirStrings = getDirs(); + if (dirStrings.contains(dirString)) { + return false; + } else { + Set dirs = new HashSet(); + dirs.addAll(dirStrings); + dirs.add(dirString); + saveDirs(dirs); + return true; + } } - private void saveDirStrings(Set gitDirStrings) { + private static void saveDirs(Set gitDirStrings) { StringBuilder sb = new StringBuilder(); for (String gitDirString : gitDirStrings) { sb.append(gitDirString); sb.append(File.pathSeparatorChar); } - IEclipsePreferences prefs = new InstanceScope().getNode(Activator - .getPluginId()); + IEclipsePreferences prefs = getPrefs(); prefs.put(PREFS_DIRECTORIES, sb.toString()); try { prefs.flush(); @@ -1429,41 +1153,6 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { } } - /** - * - * @param root - * @param strings - * @param monitor - */ - public static void recurseDir(File root, TreeSet strings, - IProgressMonitor monitor) { - - if (!root.exists() || !root.isDirectory()) { - return; - } - File[] children = root.listFiles(); - for (File child : children) { - if (monitor.isCanceled()) { - return; - } - - if (child.exists() && child.isDirectory() - && RepositoryCache.FileKey.isGitRepository(child)) { - strings.add(child.getAbsolutePath()); - return; - } - if (child.isDirectory()) { - monitor.setTaskName(child.getPath()); - recurseDir(child, strings, monitor); - } - } - - } - - private static String getRepositoryName(Repository repository) { - return repository.getDirectory().getParentFile().getName(); - } - @Override public void setFocus() { // nothing special @@ -1475,10 +1164,10 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { confirmed = MessageDialog .openConfirm( getSite().getShell(), - RepositoryViewUITexts.RepositoriesView_ConfirmProjectDeletion_WindowTitle, + UIText.RepositoriesView_ConfirmProjectDeletion_WindowTitle, NLS .bind( - RepositoryViewUITexts.RepositoriesView_ConfirmProjectDeletion_Question, + UIText.RepositoriesView_ConfirmProjectDeletion_Question, projectsToDelete.size())); return confirmed; } @@ -1505,7 +1194,62 @@ public class RepositoriesView extends ViewPart implements ISelectionProvider { } } - // private void showExceptionMessage(Exception e) { - // MessageDialog.openError(getSite().getShell(), "Error", e.getMessage()); - // } + /** + * Opens the tree and marks the folder to which a project is pointing + * + * @param resource + * TODO exceptions? + */ + @SuppressWarnings("unchecked") + public void showResource(IResource resource) { + IProject project = resource.getProject(); + RepositoryMapping mapping = RepositoryMapping.getMapping(project); + if (mapping == null) + return; + + if (addDir(mapping.getRepository().getDirectory())) { + scheduleRefresh(); + try { + scheduledJob.join(); + } catch (InterruptedException e) { + // ignore here + } + } + + RepositoriesViewContentProvider cp = (RepositoriesViewContentProvider) tv + .getContentProvider(); + RepositoryTreeNode currentNode = null; + Object[] repos = cp.getElements(tv.getInput()); + for (Object repo : repos) { + RepositoryTreeNode node = (RepositoryTreeNode) repo; + // TODO equals implementation of Repository? + if (mapping.getRepository().getDirectory().equals( + ((Repository) node.getObject()).getDirectory())) { + for (Object child : cp.getChildren(node)) { + RepositoryTreeNode childNode = (RepositoryTreeNode) child; + if (childNode.getType() == RepositoryTreeNodeType.WORKINGDIR) { + currentNode = childNode; + break; + } + } + break; + } + } + + IPath relPath = new Path(mapping.getRepoRelativePath(resource)); + + for (String segment : relPath.segments()) { + for (Object child : cp.getChildren(currentNode)) { + RepositoryTreeNode childNode = (RepositoryTreeNode) child; + if (childNode.getObject().getName().equals(segment)) { + currentNode = childNode; + break; + } + } + } + + tv.setSelection(new StructuredSelection(currentNode), true); + + } + } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java new file mode 100644 index 0000000000..7a22fd0594 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewContentProvider.java @@ -0,0 +1,271 @@ +/******************************************************************************* + * Copyright (c) 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mathias Kinzler (SAP AG) - initial implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.repository; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.egit.ui.Activator; +import org.eclipse.egit.ui.UIText; +import org.eclipse.egit.ui.internal.clone.GitProjectsImportPage; +import org.eclipse.egit.ui.internal.repository.RepositoryTreeNode.RepositoryTreeNodeType; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.osgi.util.NLS; +import org.eclipse.ui.statushandlers.StatusManager; + +/** + * Content Provider for the Git Repositories View + */ +public class RepositoriesViewContentProvider implements ITreeContentProvider { + + @SuppressWarnings("unchecked") + public Object[] getElements(Object inputElement) { + + Comparator> sorter = new Comparator>() { + + public int compare(RepositoryTreeNode o1, + RepositoryTreeNode o2) { + return getRepositoryName(o1.getObject()).compareTo( + getRepositoryName(o2.getObject())); + } + + }; + + Set> output = new TreeSet>( + sorter); + + for (Repository repo : ((List) inputElement)) { + output.add(new RepositoryTreeNode(null, + RepositoryTreeNodeType.REPO, repo, repo)); + } + + return output.toArray(); + } + + public void dispose() { + // nothing + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // nothing + } + + public Object[] getChildren(Object parentElement) { + + RepositoryTreeNode node = (RepositoryTreeNode) parentElement; + Repository repo = node.getRepository(); + + switch (node.getType()) { + + case BRANCHES: { + List> refs = new ArrayList>(); + + for (Ref ref : repo.getAllRefs().values()) { + refs.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.REF, repo, ref)); + } + + return refs.toArray(); + } + + case REMOTES: { + List> remotes = new ArrayList>(); + + Repository rep = node.getRepository(); + + Set configNames = rep.getConfig().getSubsections( + RepositoriesView.REMOTE); + + for (String configName : configNames) { + remotes.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.REMOTE, repo, configName)); + } + + return remotes.toArray(); + } + + case REPO: { + List> branches = new ArrayList>(); + + branches.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.BRANCHES, node.getRepository(), node + .getRepository())); + + branches.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.WORKINGDIR, node.getRepository(), + node.getRepository())); + + branches.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.PROJECTS, node.getRepository(), node + .getRepository())); + + branches.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.REMOTES, node.getRepository(), node + .getRepository())); + + return branches.toArray(); + } + + case PROJECTS: { + List> projects = new ArrayList>(); + + // TODO do we want to show the projects here? + Collection result = new HashSet(); + Set traversed = new HashSet(); + collectProjectFilesFromDirectory(result, repo.getDirectory() + .getParentFile(), traversed, new NullProgressMonitor()); + for (File file : result) { + projects.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.PROJ, repo, file)); + } + + Comparator> sorter = new Comparator>() { + + public int compare(RepositoryTreeNode o1, + RepositoryTreeNode o2) { + return o1.getObject().getName().compareTo( + o2.getObject().getName()); + } + }; + Collections.sort(projects, sorter); + + return projects.toArray(); + } + + case WORKINGDIR: { + List> children = new ArrayList>(); + + File workingDir = repo.getWorkDir(); + if (workingDir == null || !workingDir.exists()) + return null; + + File[] childFiles = workingDir.listFiles(); + for (File file : childFiles) { + if (file.isDirectory()) { + children.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.FOLDER, repo, file)); + } else { + children.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.FILE, repo, file)); + } + } + + return children.toArray(); + } + + case FOLDER: { + List> children = new ArrayList>(); + + File parent = ((File) node.getObject()); + + File[] childFiles = parent.listFiles(); + for (File file : childFiles) { + if (file.isDirectory()) { + children.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.FOLDER, repo, file)); + } else { + children.add(new RepositoryTreeNode(node, + RepositoryTreeNodeType.FILE, repo, file)); + } + } + + return children.toArray(); + } + + default: + return null; + } + + } + + public Object getParent(Object element) { + + return ((RepositoryTreeNode) element).getParent(); + } + + public boolean hasChildren(Object element) { + Object[] children = getChildren(element); + return children != null && children.length > 0; + } + + private boolean collectProjectFilesFromDirectory(Collection files, + File directory, Set directoriesVisited, + IProgressMonitor monitor) { + + // stolen from the GitCloneWizard; perhaps we should completely drop + // the projects from this view, though + if (monitor.isCanceled()) { + return false; + } + monitor.subTask(NLS.bind( + UIText.RepositoriesView_Checking_Message, + directory.getPath())); + File[] contents = directory.listFiles(); + if (contents == null) + return false; + + // first look for project description files + final String dotProject = IProjectDescription.DESCRIPTION_FILE_NAME; + for (int i = 0; i < contents.length; i++) { + File file = contents[i]; + if (file.isFile() && file.getName().equals(dotProject)) { + files.add(file.getParentFile()); + // don't search sub-directories since we can't have nested + // projects + return true; + } + } + // no project description found, so recurse into sub-directories + for (int i = 0; i < contents.length; i++) { + if (contents[i].isDirectory()) { + if (!contents[i].getName().equals( + GitProjectsImportPage.METADATA_FOLDER)) { + try { + String canonicalPath = contents[i].getCanonicalPath(); + if (!directoriesVisited.add(canonicalPath)) { + // already been here --> do not recurse + continue; + } + } catch (IOException exception) { + StatusManager.getManager().handle( + new Status(IStatus.ERROR, Activator + .getPluginId(), exception + .getLocalizedMessage(), exception)); + + } + collectProjectFilesFromDirectory(files, contents[i], + directoriesVisited, monitor); + } + } + } + return true; + } + + private static String getRepositoryName(Repository repository) { + return repository.getDirectory().getParentFile().getName(); + } +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java new file mode 100644 index 0000000000..3cc1e7ea93 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesViewLabelProvider.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mathias Kinzler (SAP AG) - initial implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.repository; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Path; +import org.eclipse.egit.ui.UIIcons; +import org.eclipse.egit.ui.UIText; +import org.eclipse.jface.resource.CompositeImageDescriptor; +import org.eclipse.jface.viewers.BaseLabelProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; + +/** + * Label Provider for the Git Repositories View + */ +public class RepositoriesViewLabelProvider extends BaseLabelProvider implements + ITableLabelProvider { + + // private DefaultInformationControl infoControl; + + /** + * + * @param viewer + */ + RepositoriesViewLabelProvider(final TreeViewer viewer) { + + viewer.setLabelProvider(this); + Tree tree = viewer.getTree(); + TreeColumn col = new TreeColumn(tree, SWT.NONE); + col.setWidth(400); + // we could implement some hover here to display additional information + // viewer.getTree().addMouseTrackListener(new MouseTrackAdapter() { + // + // @Override + // public void mouseHover(MouseEvent e) { + + // Point eventPoint = new Point(e.x, e.y); + // + // TreeItem item = viewer.getTree().getItem(eventPoint); + // if (item != null) { + // + // RepositoryTreeNode node = (RepositoryTreeNode) item + // .getData(); + // String text = node.getRepository().getDirectory() + // .getCanonicalPath(); + // + // final ViewerCell cell = viewer.getCell(eventPoint); + // + // if (infoControl != null && infoControl.isVisible()) { + // infoControl.setVisible(false); + // } + // + // GC testGc = new GC(cell.getControl()); + // final Point textExtent = testGc.textExtent(text); + // testGc.dispose(); + // + // if (infoControl == null || !infoControl.isVisible()) { + // + // IInformationPresenter ips = new IInformationPresenter() { + // + // public String updatePresentation( + // Display display, String hoverInfo, + // TextPresentation presentation, + // int maxWidth, int maxHeight) { + // return hoverInfo; + // } + // + // }; + // + // infoControl = new DefaultInformationControl(Display + // .getCurrent().getActiveShell().getShell(), + // ips) { + // + // @Override + // public void setInformation(String content) { + // super.setInformation(content); + // super.setSize(textExtent.x, textExtent.y); + // } + // + // }; + // } + // + // Point dispPoint = viewer.getControl().toDisplay( + // eventPoint); + // + // infoControl.setLocation(dispPoint); + // + // // the default info provider works better with \r ... + // infoControl.setInformation(text); + // + // final MouseMoveListener moveListener = new + // MouseMoveListener() { + // + // public void mouseMove(MouseEvent evt) { + // infoControl.setVisible(false); + // cell.getControl().removeMouseMoveListener(this); + // + // } + // }; + // + // cell.getControl().addMouseMoveListener(moveListener); + // + // infoControl.setVisible(true); + // + // } + // + // } + // + // }); + + } + + public Image getColumnImage(Object element, int columnIndex) { + return decorateImage( + ((RepositoryTreeNode) element).getType().getIcon(), element); + } + + public String getColumnText(Object element, int columnIndex) { + + RepositoryTreeNode node = (RepositoryTreeNode) element; + switch (node.getType()) { + case REPO: + File directory = ((Repository) node.getObject()).getDirectory(); + return (directory.getParentFile().getName() + " - " + directory //$NON-NLS-1$ + .getAbsolutePath()); + case FILE: + case FOLDER: // fall through + return ((File) node.getObject()).getName(); + case BRANCHES: + return UIText.RepositoriesView_Branches_Nodetext; + case REMOTES: + return UIText.RepositoriesView_RemotesNodeText; + case REMOTE: + return (String) node.getObject(); + case PROJECTS: + return UIText.RepositoriesView_ExistingProjects_Nodetext; + case REF: + Ref ref = (Ref) node.getObject(); + // shorten the name + String refName = node.getRepository().shortenRefName(ref.getName()); + if (ref.isSymbolic()) { + refName = refName + + " - " //$NON-NLS-1$ + + node.getRepository().shortenRefName( + ref.getLeaf().getName()); + } + return refName; + case PROJ: + + File file = (File) node.getObject(); + return file.getName(); + + case WORKINGDIR: + + return UIText.RepositoriesView_WorkingDir_treenode + + " - " //$NON-NLS-1$ + + node.getRepository().getWorkDir().getAbsolutePath(); + + default: + return null; + } + } + + private Image decorateImage(final Image image, Object element) { + + RepositoryTreeNode node = (RepositoryTreeNode) element; + switch (node.getType()) { + + case REF: + Ref ref = (Ref) node.getObject(); + // shorten the name + String refName = node.getRepository().shortenRefName(ref.getName()); + try { + String branch = node.getBranch(); + if (refName.equals(branch)) { + CompositeImageDescriptor cd = new CompositeImageDescriptor() { + + @Override + protected Point getSize() { + return new Point(image.getBounds().width, image + .getBounds().width); + } + + @Override + protected void drawCompositeImage(int width, int height) { + drawImage(image.getImageData(), 0, 0); + drawImage(UIIcons.OVR_CHECKEDOUT.getImageData(), 0, + 0); + + } + }; + return cd.createImage(); + } + } catch (IOException e1) { + // simply ignore here + } + return image; + + case PROJ: + + File file = (File) node.getObject(); + + for (IProject proj : ResourcesPlugin.getWorkspace().getRoot() + .getProjects()) { + if (proj.getLocation().equals(new Path(file.getAbsolutePath()))) { + CompositeImageDescriptor cd = new CompositeImageDescriptor() { + + @Override + protected Point getSize() { + return new Point(image.getBounds().width, image + .getBounds().width); + } + + @Override + protected void drawCompositeImage(int width, int height) { + drawImage(image.getImageData(), 0, 0); + drawImage(UIIcons.OVR_CHECKEDOUT.getImageData(), 0, + 0); + + } + }; + return cd.createImage(); + } + } + return image; + + default: + return image; + } + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySource.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySource.java index f2360428a0..93628cdc1f 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySource.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySource.java @@ -228,7 +228,6 @@ public class RepositoryPropertySource implements IPropertySource, String name; String[] valueList = null; - String value = null; if (tok.countTokens() == 2) { section = tok.nextToken(); subsection = null; @@ -242,11 +241,6 @@ public class RepositoryPropertySource implements IPropertySource, return null; } - value = config.getString(section, subsection, name); - - if (value != null) - return value; - valueList = config.getStringList(section, subsection, name); if (valueList == null || valueList.length == 0) @@ -256,7 +250,14 @@ public class RepositoryPropertySource implements IPropertySource, return valueList[0]; } - return valueList; + StringBuilder sb = new StringBuilder(); + for (String value: valueList){ + sb.append('['); + sb.append(value); + sb.append(']'); + } + + return sb.toString(); } @@ -323,11 +324,21 @@ public class RepositoryPropertySource implements IPropertySource, } categoryString = UIText.RepositoryPropertySource_RepositoryConfigurationCategory + repositoryConfig.getFile().getAbsolutePath(); + + boolean editable = true; + for (String key : configuredKeys) { + // remote stuff is not configurable + editable = !key.startsWith("remote"); //$NON-NLS-1$ + for (String sub : getSubSections(effectiveConfig, key)) { - TextPropertyDescriptor desc = new TextPropertyDescriptor( - REPO_ID_PREFIX + sub, sub); + PropertyDescriptor desc; + if (editable) + desc = new TextPropertyDescriptor(REPO_ID_PREFIX + sub, + sub); + else + desc = new PropertyDescriptor(REPO_ID_PREFIX + sub, sub); desc.setCategory(categoryString); resultList.add(desc); } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryRemotePropertySource.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryRemotePropertySource.java index 164a3edba0..b35c083000 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryRemotePropertySource.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryRemotePropertySource.java @@ -62,11 +62,14 @@ public class RepositoryRemotePropertySource implements IPropertySource { } List resultList = new ArrayList(); PropertyDescriptor desc = new PropertyDescriptor(RepositoriesView.URL, - UIText.RepositoryRemotePropertySource_RemoteUrlLabel); + UIText.RepositoryRemotePropertySource_RemoteFetchURL_label); resultList.add(desc); desc = new PropertyDescriptor(RepositoriesView.FETCH, UIText.RepositoryRemotePropertySource_FetchLabel); resultList.add(desc); + desc = new PropertyDescriptor(RepositoriesView.PUSHURL, + UIText.RepositoryRemotePropertySource_RemotePushUrl_label); + resultList.add(desc); desc = new PropertyDescriptor(RepositoriesView.PUSH, UIText.RepositoryRemotePropertySource_PushLabel); resultList.add(desc); diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositorySearchDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositorySearchDialog.java index d9a3e47fd2..142e01ed22 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositorySearchDialog.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositorySearchDialog.java @@ -11,13 +11,20 @@ package org.eclipse.egit.ui.internal.repository; import java.io.File; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.egit.core.Activator; import org.eclipse.egit.ui.UIText; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; @@ -33,11 +40,14 @@ import org.eclipse.jface.viewers.IColorProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; @@ -47,20 +57,27 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Text; +import org.osgi.service.prefs.BackingStoreException; /** * Searches for Git directories under a path that can be selected by the user */ public class RepositorySearchDialog extends Dialog { - private final Set existingRepositoryDirs = new HashSet(); + private static final String PREF_DEEP_SEARCH = "RepositorySearchDialogDeepSearch"; //$NON-NLS-1$ + + private static final String PREF_PATH = "RepositorySearchDialogSearchPath"; //$NON-NLS-1$ - private final String myInitialPath; + private final Set existingRepositoryDirs = new HashSet(); private Set result; CheckboxTableViewer tv; + private Button btnToggleSelect; + + private Table tab; + private final class ContentProvider implements IStructuredContentProvider { @SuppressWarnings("unchecked") @@ -104,15 +121,12 @@ public class RepositorySearchDialog extends Dialog { /** * @param parentShell - * @param initialPath - * the initial path * @param existingDirs */ - protected RepositorySearchDialog(Shell parentShell, String initialPath, + protected RepositorySearchDialog(Shell parentShell, Collection existingDirs) { super(parentShell); this.existingRepositoryDirs.addAll(existingDirs); - this.myInitialPath = initialPath; setShellStyle(getShellStyle() | SWT.SHELL_TRIM); } @@ -127,7 +141,8 @@ public class RepositorySearchDialog extends Dialog { @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); - newShell.setText(UIText.RepositorySearchDialog_SearchRepositoriesHeader); + newShell + .setText(UIText.RepositorySearchDialog_SearchRepositoriesHeader); } @Override @@ -143,21 +158,27 @@ public class RepositorySearchDialog extends Dialog { @Override protected Control createDialogArea(Composite parent) { - Composite main = new Composite(parent, SWT.NONE); - main.setLayout(new GridLayout(3, false)); + final IEclipsePreferences prefs = new InstanceScope().getNode(Activator + .getPluginId()); - GridDataFactory.fillDefaults().grab(true, true).applyTo(main); + Composite main = new Composite(parent, SWT.NONE); + main.setLayout(new GridLayout(4, false)); + main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Label dirLabel = new Label(main, SWT.NONE); dirLabel.setText(UIText.RepositorySearchDialog_DirectoryLabel); - final Text dir = new Text(main, SWT.NONE); - if (myInitialPath != null) - dir.setText(myInitialPath); + final Text dir = new Text(main, SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).span(2, 1).hint(300, + SWT.DEFAULT).applyTo(dir); - GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, - false).applyTo(dir); + String initialPath = prefs.get(PREF_PATH, ResourcesPlugin + .getWorkspace().getRoot().getLocation().toOSString()); + + dir.setText(initialPath); Button browse = new Button(main, SWT.PUSH); + browse.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, + 1, 1)); browse.setText(UIText.RepositorySearchDialog_BrowseButton); browse.addSelectionListener(new SelectionAdapter() { @@ -168,19 +189,73 @@ public class RepositorySearchDialog extends Dialog { String directory = dd.open(); if (directory != null) { dir.setText(directory); + prefs.put(PREF_PATH, directory); + try { + prefs.flush(); + } catch (BackingStoreException e1) { + // ignore here + } + } + } + + }); + + // we fill the room under the "Directory" label + new Label(main, SWT.NONE); + + final Button btnLookForNested = new Button(main, SWT.CHECK); + btnLookForNested.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, + false, false, 2, 1)); + btnLookForNested + .setSelection(prefs.getBoolean(PREF_DEEP_SEARCH, false)); + btnLookForNested + .setText(UIText.RepositorySearchDialog_DeepSearch_button); + + btnLookForNested.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + prefs.putBoolean(PREF_DEEP_SEARCH, btnLookForNested + .getSelection()); + try { + prefs.flush(); + } catch (BackingStoreException e1) { + // ignore } } }); Button search = new Button(main, SWT.PUSH); + search.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, + 1, 1)); search.setText(UIText.RepositorySearchDialog_SearchButton); - GridDataFactory.fillDefaults().align(SWT.LEAD, SWT.CENTER).span(3, 1) - .applyTo(search); tv = CheckboxTableViewer.newCheckList(main, SWT.NONE); - Table tab = tv.getTable(); - GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(tab); + tab = tv.getTable(); + tab.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); + tab.setEnabled(false); + + btnToggleSelect = new Button(main, SWT.NONE); + btnToggleSelect.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, + false, 1, 1)); + btnToggleSelect + .setText(UIText.RepositorySearchDialog_ToggleSelection_button); + btnToggleSelect.setEnabled(false); + btnToggleSelect.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + + for (int i = 0; i < tab.getItemCount(); i++) { + if (!existingRepositoryDirs.contains(tv.getElementAt(i))) + tv.setChecked(tv.getElementAt(i), !tv.getChecked(tv + .getElementAt(i))); + } + getButton(IDialogConstants.OK_ID).setEnabled( + tv.getCheckedElements().length > 0); + } + }); tv.addCheckStateListener(new ICheckStateListener() { @@ -201,28 +276,64 @@ public class RepositorySearchDialog extends Dialog { public void widgetSelected(SelectionEvent e) { final TreeSet directories = new TreeSet(); final File file = new File(dir.getText()); + final boolean lookForNested = btnLookForNested.getSelection(); if (file.exists()) { + try { + prefs.put(PREF_PATH, file.getCanonicalPath()); + try { + prefs.flush(); + } catch (BackingStoreException e1) { + // ignore here + } + } catch (IOException e2) { + // ignore + } + IRunnableWithProgress action = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - RepositoriesView.recurseDir(file, directories, - monitor); + + try { + findGitDirsRecursive(file, directories, + monitor, lookForNested); + } catch (Exception ex) { + Activator.getDefault().getLog().log( + new Status(IStatus.ERROR, Activator + .getPluginId(), + ex.getMessage(), ex)); + } } }; try { ProgressMonitorDialog pd = new ProgressMonitorDialog( getShell()); + pd + .getProgressMonitor() + .setTaskName( + UIText.RepositorySearchDialog_ScanningForRepositories_message); pd.run(true, true, action); } catch (InvocationTargetException e1) { - MessageDialog.openError(getShell(), UIText.RepositorySearchDialog_ErrorHeader, e1 - .getCause().getMessage()); + MessageDialog.openError(getShell(), + UIText.RepositorySearchDialog_ErrorHeader, e1 + .getCause().getMessage()); } catch (InterruptedException e1) { // ignore } + boolean foundNew = false; + + for (String foundDir : directories) { + if (!existingRepositoryDirs.contains(foundDir)) { + foundNew = true; + break; + } + } + + btnToggleSelect.setEnabled(foundNew); + tab.setEnabled(directories.size() > 0); tv.setInput(directories); } } @@ -240,4 +351,43 @@ public class RepositorySearchDialog extends Dialog { return bar; } + private void findGitDirsRecursive(File root, TreeSet strings, + IProgressMonitor monitor, boolean lookForNestedRepositories) { + + if (!root.exists() || !root.isDirectory()) { + return; + } + File[] children = root.listFiles(); + // simply ignore null + if (children == null) + return; + + for (File child : children) { + if (monitor.isCanceled()) { + return; + } + + if (child.isDirectory() + && RepositoryCache.FileKey.isGitRepository(child)) { + try { + strings.add(child.getCanonicalPath()); + } catch (IOException e) { + // ignore here + } + monitor + .setTaskName(NLS + .bind( + UIText.RepositorySearchDialog_RepositoriesFound_message, + new Integer(strings.size()))); + if (!lookForNestedRepositories) + return; + } else if (child.isDirectory()) { + monitor.subTask(child.getPath()); + findGitDirsRecursive(child, strings, monitor, + lookForNestedRepositories); + } + } + + } + } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNode.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNode.java index c0487fe7bc..f1fbc74202 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNode.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNode.java @@ -143,7 +143,9 @@ class RepositoryTreeNode { switch (myType) { case REPO: case PROJECTS: + case REMOTES: case BRANCHES: + case WORKINGDIR: result = prime * result + ((myObject == null) ? 0 : ((Repository) myObject) @@ -156,14 +158,17 @@ class RepositoryTreeNode { .hashCode()); break; case PROJ: + case FILE: + case FOLDER: result = prime * result + ((myObject == null) ? 0 : ((File) myObject).getPath() .hashCode()); break; + case REMOTE: + result = prime * result + + ((myObject == null) ? 0 : myObject.hashCode()); - default: - break; } result = prime * result @@ -218,16 +223,19 @@ class RepositoryTreeNode { case PROJECTS: case REMOTES: case BRANCHES: + case WORKINGDIR: return ((Repository) myObject).getDirectory().equals( ((Repository) otherObject).getDirectory()); case REF: return ((Ref) myObject).getName().equals( ((Ref) otherObject).getName()); case PROJ: + case FOLDER: + case FILE: return ((File) myObject).getPath().equals( ((File) otherObject).getPath()); case REMOTE: - return myObject.equals(otherObject); + return myObject.equals(otherObject); } return false; } @@ -240,10 +248,16 @@ class RepositoryTreeNode { PROJ(PlatformUI.getWorkbench().getSharedImages().getImage( SharedImages.IMG_OBJ_PROJECT_CLOSED)), // BRANCHES(UIIcons.BRANCHES.createImage()), // - PROJECTS(PlatformUI.getWorkbench().getSharedImages().getImage( + FILE(PlatformUI.getWorkbench().getSharedImages().getImage( + ISharedImages.IMG_OBJ_FILE)), // + FOLDER(PlatformUI.getWorkbench().getSharedImages().getImage( ISharedImages.IMG_OBJ_FOLDER)), // + PROJECTS(PlatformUI.getWorkbench().getSharedImages().getImage( + SharedImages.IMG_OBJ_PROJECT_CLOSED)), // REMOTES(UIIcons.REMOTE_REPOSITORY.createImage()), // REMOTE(PlatformUI.getWorkbench().getSharedImages().getImage( + ISharedImages.IMG_OBJ_FOLDER)), // + WORKINGDIR(PlatformUI.getWorkbench().getSharedImages().getImage( ISharedImages.IMG_OBJ_FOLDER)) ; diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryViewUITexts.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryViewUITexts.java deleted file mode 100644 index fb8a9e2dd9..0000000000 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryViewUITexts.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 SAP AG. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Mathias Kinzler (SAP AG) - initial implementation - *******************************************************************************/ -package org.eclipse.egit.ui.internal.repository; - -import org.eclipse.osgi.util.NLS; - -/** - * UI Texts for the Repositories View - * - */ -public class RepositoryViewUITexts extends NLS { - private static final String BUNDLE_NAME = "org.eclipse.egit.ui.internal.repository.repositoryviewuitexts"; //$NON-NLS-1$ - - /** */ - public static String RepositoriesView_ActionCanceled_Message; - - /** */ - public static String RepositoriesView_Add_Button; - - /** */ - public static String RepositoriesView_AddRepository_MenuItem; - - /** */ - public static String RepositoriesView_AddRepository_Tooltip; - - /** */ - public static String RepositoriesView_Branches_Nodetext; - - /** */ - public static String RepositoriesView_Checking_Message; - - /** */ - public static String RepositoriesView_CheckOut_MenuItem; - - /** */ - public static String RepositoriesView_Clone_Tooltip; - - /** */ - public static String RepositoriesView_ConfigureFetchMenu; - - /** */ - public static String RepositoriesView_ConfigurePushMenu; - - /** */ - public static String RepositoriesView_ConfirmDeleteRemoteHeader; - - /** */ - public static String RepositoriesView_ConfirmDeleteRemoteMessage; - - /** */ - public static String RepositoriesView_ConfirmProjectDeletion_Question; - - /** */ - public static String RepositoriesView_ConfirmProjectDeletion_WindowTitle; - - /** */ - public static String RepositoriesView_Error_WindowTitle; - - /** */ - public static String RepositoriesView_ErrorHeader; - - /** */ - public static String RepositoriesView_ExistingProjects_Nodetext; - - /** */ - public static String RepositoriesView_Import_Button; - - /** */ - public static String RepositoriesView_ImportExistingProjects_MenuItem; - - /** */ - public static String RepositoriesView_ImportProject_MenuItem; - - /** */ - public static String RepositoriesView_ImportRepository_MenuItem; - - /** */ - public static String RepositoriesView_NewRemoteMenu; - - /** */ - public static String RepositoriesView_OpenPropertiesMenu; - - /** */ - public static String RepositoriesView_Refresh_Button; - - /** */ - public static String RepositoriesView_RemotesNodeText; - - /** */ - public static String RepositoriesView_Remove_MenuItem; - - /** */ - public static String RepositoriesView_RemoveRemoteMenu; - - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, RepositoryViewUITexts.class); - } - -} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/SelectRemoteNamePage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/SelectRemoteNamePage.java index 4ebc6e9555..0438dd5d17 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/SelectRemoteNamePage.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/SelectRemoteNamePage.java @@ -16,7 +16,10 @@ import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; @@ -28,6 +31,10 @@ public class SelectRemoteNamePage extends WizardPage { Text remoteName; + Button configureFetch; + + Button configurePush; + /** * */ @@ -57,6 +64,31 @@ public class SelectRemoteNamePage extends WizardPage { } }); + configureFetch = new Button(main, SWT.CHECK); + configureFetch.setText("Configure Fetch"); + configureFetch.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + checkPage(); + } + + }); + + GridDataFactory.fillDefaults().span(2, 1).applyTo(configureFetch); + + configurePush = new Button(main, SWT.CHECK); + configurePush.setText("Configure Push"); + configurePush.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + checkPage(); + } + + }); + GridDataFactory.fillDefaults().span(2, 1).applyTo(configurePush); + setControl(main); setPageComplete(false); @@ -76,6 +108,12 @@ public class SelectRemoteNamePage extends WizardPage { setErrorMessage(UIText.SelectRemoteNamePage_NameInUseMessage); return; } + + if (!configureFetch.getSelection() && !configurePush.getSelection()) { + setErrorMessage("You must select one configuration checkbox"); + return; + } + } finally { setPageComplete(getErrorMessage() == null); } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/repositoryviewuitexts.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/repositoryviewuitexts.properties deleted file mode 100644 index df3161a54b..0000000000 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/repositoryviewuitexts.properties +++ /dev/null @@ -1,27 +0,0 @@ -RepositoriesView_ActionCanceled_Message=Action was canceled -RepositoriesView_Add_Button=Add... -RepositoriesView_AddRepository_MenuItem=Add Git Repository... -RepositoriesView_AddRepository_Tooltip=Add an existing Git Repository -RepositoriesView_Branches_Nodetext=Branches -RepositoriesView_Checking_Message=Checking: {0} -RepositoriesView_CheckOut_MenuItem=Check out -RepositoriesView_Clone_Tooltip=Import (clone) a Git Repository -RepositoriesView_ConfigureFetchMenu=Configure remote fetch... -RepositoriesView_ConfigurePushMenu=Configure remote push... -RepositoriesView_ConfirmDeleteRemoteHeader=Confirm deletion of remote configuration -RepositoriesView_ConfirmDeleteRemoteMessage=This will remove remote configuration {0} completely, are you sure? -RepositoriesView_ConfirmProjectDeletion_Question={0} projects must be deleted, continue? -RepositoriesView_ConfirmProjectDeletion_WindowTitle=Confirm project deletion -RepositoriesView_Error_WindowTitle=Error -RepositoriesView_ErrorHeader=Error -RepositoriesView_ExistingProjects_Nodetext=Existing Projects -RepositoriesView_Import_Button=Import... -RepositoriesView_ImportExistingProjects_MenuItem=Import Existing projects... -RepositoriesView_ImportProject_MenuItem=Import -RepositoriesView_ImportRepository_MenuItem=Import Git Repository... -RepositoriesView_NewRemoteMenu=New remote... -RepositoriesView_OpenPropertiesMenu=Open Properties view -RepositoriesView_Refresh_Button=Refresh -RepositoriesView_RemotesNodeText=Remotes -RepositoriesView_Remove_MenuItem=Remove -RepositoriesView_RemoveRemoteMenu=Remove remote... diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties index aba35d4115..fbe03d6f22 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties @@ -72,14 +72,19 @@ RepositoryPropertySource_GlobalConfigurationCategory=Global configuration RepositoryPropertySource_RepositoryConfigurationCategory=Repository configuration RepositoryPropertySource_RestoreStandardAction=Restore standard keys RepositoryRemotePropertySource_ErrorHeader=Error -RepositoryRemotePropertySource_FetchLabel=Remote Fetch -RepositoryRemotePropertySource_PushLabel=Remote Push -RepositoryRemotePropertySource_RemoteUrlLabel=Remote URL +RepositoryRemotePropertySource_FetchLabel=Remote Fetch Specification +RepositoryRemotePropertySource_PushLabel=Remote Push Specification +RepositoryRemotePropertySource_RemoteFetchURL_label=Remote Fetch URL +RepositoryRemotePropertySource_RemotePushUrl_label=Remote Push URL RepositorySearchDialog_BrowseButton=Browse... +RepositorySearchDialog_DeepSearch_button=Look for Nested Repositories RepositorySearchDialog_DirectoryLabel=Directory RepositorySearchDialog_ErrorHeader=Error +RepositorySearchDialog_RepositoriesFound_message={0} Git repositories found... +RepositorySearchDialog_ScanningForRepositories_message=Scanning for GIT repositories... RepositorySearchDialog_SearchButton=Search RepositorySearchDialog_SearchRepositoriesHeader=Search Git Repositories +RepositorySearchDialog_ToggleSelection_button=Toggle Selection RepositorySelectionPage_BrowseLocalFile=Local file... RepositorySelectionPage_sourceSelectionTitle=Source Git Repository RepositorySelectionPage_sourceSelectionDescription=Enter the location of the source repository. @@ -443,3 +448,34 @@ IgnoreAction_taskName=Ignoring Git resources IgnoreAction_error=Unable to ignore resources Track_error=Add to Version Control failed Track_see_log=See error log for details. + +RepositoriesView_ActionCanceled_Message=Action was canceled +RepositoriesView_Add_Button=Add... +RepositoriesView_AddRepository_MenuItem=Add Git Repository... +RepositoriesView_AddRepository_Tooltip=Add an existing Git Repository +RepositoriesView_Branches_Nodetext=Branches +RepositoriesView_Checking_Message=Checking: {0} +RepositoriesView_CheckOut_MenuItem=Check out +RepositoriesView_Clone_Tooltip=Import (clone) a Git Repository +RepositoriesView_ConfigureFetchMenu=Configure remote fetch... +RepositoriesView_ConfigurePushMenu=Configure remote push... +RepositoriesView_ConfirmDeleteRemoteHeader=Confirm deletion of remote configuration +RepositoriesView_ConfirmDeleteRemoteMessage=This will remove remote configuration {0} completely, are you sure? +RepositoriesView_ConfirmProjectDeletion_Question={0} projects must be deleted, continue? +RepositoriesView_ConfirmProjectDeletion_WindowTitle=Confirm project deletion +RepositoriesView_Error_WindowTitle=Error +RepositoriesView_ErrorHeader=Error +RepositoriesView_ExistingProjects_Nodetext=Existing Projects +RepositoriesView_Import_Button=Import... +RepositoriesView_ImportExistingProjects_MenuItem=Import Existing projects... +RepositoriesView_ImportProject_MenuItem=Import +RepositoriesView_ImportRepository_MenuItem=Import Git Repository... +RepositoriesView_LinkWithSelection_action=Link with selection +RepositoriesView_NewRemoteMenu=New remote... +RepositoriesView_OpenInTextEditor_menu=Open in text editor +RepositoriesView_OpenPropertiesMenu=Open Properties view +RepositoriesView_Refresh_Button=Refresh +RepositoriesView_RemotesNodeText=Remotes +RepositoriesView_Remove_MenuItem=Remove +RepositoriesView_RemoveRemoteMenu=Remove remote... +RepositoriesView_WorkingDir_treenode=Working directory \ No newline at end of file -- cgit v1.2.3