diff options
author | Mathias Kinzler | 2010-03-24 06:50:59 +0000 |
---|---|---|
committer | Mathias Kinzler | 2010-03-26 13:23:00 +0000 |
commit | b43494e82a187fbd6be96bf4b11cf96da66e1dcb (patch) | |
tree | 63f40df06f2c3f129f0fca0a620d3a6579e2876d /org.eclipse.egit.ui/src | |
parent | 14ac3efaab9305704a864903de54c76e33dd4043 (diff) | |
download | egit-b43494e82a187fbd6be96bf4b11cf96da66e1dcb.tar.gz egit-b43494e82a187fbd6be96bf4b11cf96da66e1dcb.tar.xz egit-b43494e82a187fbd6be96bf4b11cf96da66e1dcb.zip |
Add Configuration to Repositories View
This adds two things: first, support for the standard
"Properties" view in Eclipse which allows to maintain
simple properties, like user name and email directly and
secondly, it adds a "Remotes" node to the Repositories
View which allows to maintain remote configurations
(re-using the existing wizard pages as much as possible).
Bug: 304182 (and 295995)
Change-Id: I3b4528a9e50cfcc13fe98e2468c2e8df02c53f4b
Signed-off-by: Mathias Kinzler <mathias.kinzler@sap.com>
Diffstat (limited to 'org.eclipse.egit.ui/src')
17 files changed, 1963 insertions, 395 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java index cd8f92a5c1..d9b05fa4d2 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java @@ -51,16 +51,6 @@ import org.eclipse.jgit.transport.SshSessionFactory; */ public class Activator extends AbstractUIPlugin { - /** the repository icon */ - public static final String ICON_REPOSITORY = "Icon_Repository"; //$NON-NLS-1$ - - /** the branches icon */ - public static final String ICON_BRANCHES = "Icon_Branches"; //$NON-NLS-1$ - - /** the checked-out overlay icon */ - public static final String ICON_CHECKEDOUT_OVR = "Icon_CheckedOut_Overlay"; //$NON-NLS-1$ - - /** * The one and only instance */ @@ -206,13 +196,6 @@ public class Activator extends AbstractUIPlugin { setupProxy(context); setupRepoChangeScanner(); setupRepoIndexRefresh(); - setupImageRegistry(); - } - - private void setupImageRegistry() { - getImageRegistry().put(ICON_REPOSITORY, imageDescriptorFromPlugin(getPluginId(), "icons/obj16/repository_rep.gif")); //$NON-NLS-1$ - getImageRegistry().put(ICON_BRANCHES, imageDescriptorFromPlugin(getPluginId(), "icons/obj16/branches_rep.gif")); //$NON-NLS-1$ - getImageRegistry().put(ICON_CHECKEDOUT_OVR, imageDescriptorFromPlugin(getPluginId(), "icons/ovr/checkedout_ov.gif")); //$NON-NLS-1$ } private void setupRepoIndexRefresh() { 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 1b165bf35a..c72d663890 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 @@ -60,6 +60,8 @@ public class UIIcons { public static final ImageDescriptor ELCL16_TRASH; /** Clear icon */ public static final ImageDescriptor ELCL16_CLEAR; + /** Refresh icon */ + public static final ImageDescriptor ELCL16_REFRESH; /** Enabled, checked, checkbox image */ public static final ImageDescriptor CHECKBOX_ENABLED_CHECKED; @@ -85,6 +87,24 @@ public class UIIcons { /** History filter, select all version in same folder */ public static ImageDescriptor FILTERFOLDER; + /** Import button */ + public static ImageDescriptor IMPORT; + + /** Repository tree node */ + public static ImageDescriptor REPOSITORY; + + /** New Repository button */ + public static ImageDescriptor NEW_REPOSITORY; + + /** Remote Repository tree node */ + public static ImageDescriptor REMOTE_REPOSITORY; + + /** Branches tree node */ + public static ImageDescriptor BRANCHES; + + /** Checked-out decorator for branch */ + public static ImageDescriptor OVR_CHECKEDOUT; + private static final URL base; static { @@ -108,6 +128,7 @@ public class UIIcons { ELCL16_ADD = map("elcl16/add.gif"); //$NON-NLS-1$ 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$ 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$ @@ -115,6 +136,12 @@ public class UIIcons { FILTERREPO = map("elcl16/filterrepo.gif"); //$NON-NLS-1$ FILTERPROJECT = map("elcl16/filterproject.gif"); //$NON-NLS-1$ FILTERFOLDER = map("elcl16/filterfolder.gif"); //$NON-NLS-1$ + IMPORT = map("etool16/import_wiz.gif"); //$NON-NLS-1$ + REPOSITORY = map("obj16/repository_rep.gif"); //$NON-NLS-1$ + NEW_REPOSITORY = map("etool16/newlocation_wiz.gif"); //$NON-NLS-1$ + REMOTE_REPOSITORY = map("obj16/remote_entry_tbl.gif"); //$NON-NLS-1$ + BRANCHES = map("obj16/branches_rep.gif"); //$NON-NLS-1$ + OVR_CHECKEDOUT = map("ovr/checkedout_ov.gif"); //$NON-NLS-1$ } private static ImageDescriptor map(final String icon) { 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 6926529bdb..525b7b8ba2 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 @@ -70,6 +70,24 @@ public class UIText extends NLS { public static String WizardProjectsImportPage_enableGit; /** */ + public static String SelectRemoteNamePage_NameInUseMessage; + + /** */ + public static String SelectRemoteNamePage_NameMustNotBeEmptyMessage; + + /** */ + public static String SelectRemoteNamePage_RemoteNameLabel; + + /** */ + public static String SelectRemoteNamePage_RemoteNameMessage; + + /** */ + public static String SelectRemoteNamePage_RemoteNameTitle; + + /** */ + public static String SelectRemoteNamePage_SelectRemoteNameMessage; + + /** */ public static String SharingWizard_windowTitle; /** */ @@ -157,6 +175,54 @@ public class UIText extends NLS { public static String GitProjectPropertyPage_ValueUnbornBranch; /** */ + public static String RepositoryPropertySource_ConfigureKeysAction; + + /** */ + public static String RepositoryPropertySource_EffectiveConfigurationAction; + + /** */ + public static String RepositoryPropertySource_EffectiveConfigurationCategory; + + /** */ + public static String RepositoryPropertySource_ErrorHeader; + + /** */ + public static String RepositoryPropertySource_GlobalConfigurationCategory; + + /** */ + public static String RepositoryPropertySource_RepositoryConfigurationCategory; + + /** */ + public static String RepositoryPropertySource_RestoreStandardAction; + + /** */ + public static String RepositoryRemotePropertySource_ErrorHeader; + + /** */ + public static String RepositoryRemotePropertySource_FetchLabel; + + /** */ + public static String RepositoryRemotePropertySource_PushLabel; + + /** */ + public static String RepositoryRemotePropertySource_RemoteUrlLabel; + + /** */ + public static String RepositorySearchDialog_BrowseButton; + + /** */ + public static String RepositorySearchDialog_DirectoryLabel; + + /** */ + public static String RepositorySearchDialog_ErrorHeader; + + /** */ + public static String RepositorySearchDialog_SearchButton; + + /** */ + public static String RepositorySearchDialog_SearchRepositoriesHeader; + + /** */ public static String RepositorySelectionPage_BrowseLocalFile; /** */ @@ -709,6 +775,30 @@ public class UIText extends NLS { public static String CommitDialog_StatusUnknown; /** */ + public static String ConfigureKeysDialog_AddStandardButton; + + /** */ + public static String ConfigureKeysDialog_AlreadyThere_Message; + + /** */ + public static String ConfigureKeysDialog_DeleteButton; + + /** */ + public static String ConfigureKeysDialog_DialogTitle; + + /** */ + public static String ConfigureKeysDialog_NewButton; + + /** */ + public static String ConfigureKeysDialog_NewKeyLabel; + + /** */ + public static String ConfigureRemoteWizard_WizardTitle_Change; + + /** */ + public static String ConfigureRemoteWizard_WizardTitle_New; + + /** */ public static String ConfirmationPage_cantConnectToAnyTitle; /** */ 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 68f0ad7278..c05d93c33a 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,6 +67,13 @@ 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; + /** * Create specifications selection page for provided context. * @@ -78,10 +85,13 @@ 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) { + final RepositorySelectionPage repoPage, String remoteName) { super(RefSpecPage.class.getName()); + this.remoteName = remoteName; this.local = local; this.repoPage = repoPage; this.pushPage = pushPage; @@ -103,6 +113,23 @@ 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()); @@ -252,13 +279,21 @@ public class RefSpecPage extends BaseWizardPage { } this.validatedRepoSelection = newRepoSelection; - final String remoteName = validatedRepoSelection.getConfigName(); + final String actRemoteName; + if (remoteName == null) + actRemoteName = validatedRepoSelection.getConfigName(); + else + actRemoteName = remoteName; + if (initialSpecSize < 0) + initialSpecSize = listRemotesOp.getRemoteRefs().size(); specsPanel.setAssistanceData(local, listRemotesOp.getRemoteRefs(), - remoteName); + actRemoteName); - tagsAutoFollowButton.setSelection(false); - tagsFetchTagsButton.setSelection(false); - tagsNoTagsButton.setSelection(false); + if (!pushPage) { + tagsAutoFollowButton.setSelection(false); + tagsFetchTagsButton.setSelection(false); + tagsNoTagsButton.setSelection(false); + } if (newRepoSelection.isConfigSelected()) { saveButton.setVisible(true); @@ -277,7 +312,7 @@ public class RefSpecPage extends BaseWizardPage { tagsNoTagsButton.setSelection(true); break; } - } else + } else if (!pushPage) tagsAutoFollowButton.setSelection(true); checkPage(); @@ -301,6 +336,6 @@ public class RefSpecPage extends BaseWizardPage { return; } setErrorMessage(specsPanel.getErrorMessage()); - setPageComplete(!specsPanel.isEmpty() && specsPanel.isValid()); + setPageComplete(initialSpecSize > 0 || (!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 b6b9657aa5..6f2233d580 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 @@ -140,6 +140,8 @@ public class RepositorySelectionPage extends BaseWizardPage { private Button uriButton; + private String presetUri; + /** * Create repository selection page, allowing user specifying URI or * (optionally) choosing from preconfigured remotes list. @@ -196,6 +198,16 @@ public class RepositorySelectionPage extends BaseWizardPage { } /** + * 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. */ public RepositorySelection getSelection() { @@ -224,6 +236,9 @@ public class RepositorySelectionPage extends BaseWizardPage { updateRemoteAndURIPanels(); setControl(panel); + if (presetUri != null) + uriText.setText(presetUri); + checkPage(); } @@ -525,7 +540,7 @@ public class RepositorySelectionPage extends BaseWizardPage { } private boolean isURISelected() { - return configuredRemotes == null || uriButton.getSelection(); + return configuredRemotes == null || presetUri != null || uriButton.getSelection(); } private void setURI(final URIish u) { diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureKeysDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureKeysDialog.java new file mode 100644 index 0000000000..9a70c32c72 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureKeysDialog.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * 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.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.egit.ui.UIText; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.viewers.BaseLabelProvider; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.window.Window; +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.Image; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +/** + * Configures the Git configuration keys to display in the Properties view + */ +class ConfigureKeysDialog extends Dialog { + + private static final class ContentProvider implements + IStructuredContentProvider { + + public Object[] getElements(Object inputElement) { + return ((List) inputElement).toArray(); + } + + public void dispose() { + // nothing + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // nothing + } + + } + + private static final class LabelProvider extends BaseLabelProvider + implements ITableLabelProvider { + + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + + public String getColumnText(Object element, int columnIndex) { + return (String) element; + } + + } + + /** + * The standard keys + */ + public static final List<String> standardKeys = new ArrayList<String>(); + + static { + standardKeys.add("core.logallrefupdates"); //$NON-NLS-1$ + standardKeys.add("core.compression"); //$NON-NLS-1$ + + standardKeys.add("remote.?.url"); //$NON-NLS-1$ + standardKeys.add("remote.?.fetch"); //$NON-NLS-1$ + standardKeys.add("remote.?.push"); //$NON-NLS-1$ + + standardKeys.add("user.name"); //$NON-NLS-1$ + standardKeys.add("user.email"); //$NON-NLS-1$ + + Collections.sort(standardKeys); + } + + private final List<String> activeKeys = new ArrayList<String>(); + + /** + * @param parentShell + * @param activeKeys + */ + ConfigureKeysDialog(Shell parentShell, List<String> activeKeys) { + super(parentShell); + this.activeKeys.addAll(activeKeys); + setShellStyle(getShellStyle() | SWT.SHELL_TRIM); + } + + /** + * @return the strings + */ + public List<String> getActiveKeys() { + return activeKeys; + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText(UIText.ConfigureKeysDialog_DialogTitle); + } + + @Override + protected Control createDialogArea(Composite parent) { + + Composite main = new Composite(parent, SWT.NONE); + main.setLayout(new GridLayout(1, false)); + GridDataFactory.fillDefaults().grab(true, true).applyTo(main); + + final CheckboxTableViewer tv = CheckboxTableViewer.newCheckList(main, + SWT.NONE); + + GridDataFactory.fillDefaults().grab(true, true).applyTo(tv.getTable()); + + ToolBar tb = new ToolBar(main, SWT.HORIZONTAL); + final ToolItem del = new ToolItem(tb, SWT.PUSH); + del.setEnabled(false); + del.setText(UIText.ConfigureKeysDialog_DeleteButton); + del.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + for (Object ob : tv.getCheckedElements()) { + activeKeys.remove(ob); + tv.setInput(activeKeys); + } + } + + }); + + final ToolItem addStandard = new ToolItem(tb, SWT.PUSH); + addStandard.setText(UIText.ConfigureKeysDialog_AddStandardButton); + addStandard.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + for (String key : standardKeys) { + if (!activeKeys.contains(key)) { + activeKeys.add(key); + } + tv.setInput(activeKeys); + } + Collections.sort(activeKeys); + } + + }); + + ToolItem add = new ToolItem(tb, SWT.PUSH); + add.setText(UIText.ConfigureKeysDialog_NewButton); + add.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + IInputValidator validator = new IInputValidator() { + + public String isValid(String newText) { + if (activeKeys.contains(newText)) + return NLS + .bind( + UIText.ConfigureKeysDialog_AlreadyThere_Message, + newText); + return null; + } + }; + InputDialog id = new InputDialog(getShell(), + UIText.ConfigureKeysDialog_NewKeyLabel, + UIText.ConfigureKeysDialog_NewKeyLabel, null, validator); + if (id.open() == Window.OK) { + activeKeys.add(id.getValue()); + Collections.sort(activeKeys); + tv.setInput(activeKeys); + } + } + + }); + + tv.addCheckStateListener(new ICheckStateListener() { + + public void checkStateChanged(CheckStateChangedEvent event) { + boolean anyChecked = tv.getCheckedElements().length > 0; + del.setEnabled(anyChecked); + + } + }); + + tv.setLabelProvider(new LabelProvider()); + tv.setContentProvider(new ContentProvider()); + tv.setInput(this.activeKeys); + + return main; + } +} 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 new file mode 100644 index 0000000000..8162eb0734 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/ConfigureRemoteWizard.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * 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.IOException; +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.Wizard; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryConfig; +import org.eclipse.jgit.transport.RemoteConfig; +import org.eclipse.osgi.util.NLS; + +/** + * Used for "remote" configuration of a Repository + */ +class ConfigureRemoteWizard extends Wizard { + + final RepositoryConfig myConfiguration; + + final boolean pushMode; + + final String myRemoteName; + + /** + * @param repository + */ + public ConfigureRemoteWizard(Repository repository) { + this(repository, null, false); + } + + /** + * + * @param repository + * @param remoteName + * @param push + */ + public ConfigureRemoteWizard(Repository repository, String remoteName, + boolean push) { + myConfiguration = repository.getConfig(); + myRemoteName = remoteName; + pushMode = push; + if (myRemoteName == null) { + // create mode: add remote name page and repository selection page + addPage(new SelectRemoteNamePage()); + addPage(new RepositorySelectionPage(null)); + 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)); + + addPage(sp); + // and also the corresponding configuration page + RefSpecPage rsp = new RefSpecPage(repository, pushMode, sp, + myRemoteName); + addPage(rsp); + setWindowTitle(NLS.bind( + UIText.ConfigureRemoteWizard_WizardTitle_Change, + myRemoteName)); + } + + } + + /** + * @return the configuration + * + */ + public RepositoryConfig getConfiguration() { + return myConfiguration; + } + + @Override + public boolean performFinish() { + + String actRemoteName = myRemoteName; + if (myRemoteName == null) { + SelectRemoteNamePage page = (SelectRemoteNamePage) getPage(SelectRemoteNamePage.class + .getName()); + actRemoteName = page.remoteName.getText(); + } + + RepositorySelectionPage sp = (RepositorySelectionPage) getPage(RepositorySelectionPage.class + .getName()); + + String uriString = sp.getSelection().getURI().toString(); + + myConfiguration.setString(RepositoriesView.REMOTE, actRemoteName, + RepositoriesView.URL, uriString); + + if (myRemoteName != null) { + + 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); + } catch (URISyntaxException e1) { + // TODO better Exception handling + return false; + } + + if (pushMode) + config.setPushRefSpecs(specPage.getRefSpecs()); + else { + config.setFetchRefSpecs(specPage.getRefSpecs()); + config.setTagOpt(specPage.getTagOpt()); + } + config.update(myConfiguration); + } + + try { + myConfiguration.save(); + return true; + } catch (IOException e) { + // TODO better Exception handling + return false; + } + } + +} 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 25a9b94086..0b754dadea 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 @@ -41,41 +41,41 @@ 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.ui.Activator; +import org.eclipse.egit.ui.UIIcons; 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.resource.ImageDescriptor; -import org.eclipse.jface.text.DefaultInformationControl; -import org.eclipse.jface.text.TextPresentation; -import org.eclipse.jface.text.DefaultInformationControl.IInformationPresenter; 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.viewers.ViewerCell; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.Wizard; import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.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.MouseMoveListener; import org.eclipse.swt.events.MouseTrackAdapter; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridLayout; @@ -86,12 +86,16 @@ 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.ISharedImages; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.ide.IDE.SharedImages; 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; import org.eclipse.ui.wizards.datatransfer.ExternalProjectImportWizard; import org.osgi.service.prefs.BackingStoreException; @@ -109,13 +113,22 @@ import org.osgi.service.prefs.BackingStoreException; * <li>Clarification whether to show projects, perhaps configurable switch</li> * */ -public class RepositoriesView extends ViewPart { +public class RepositoriesView extends ViewPart implements ISelectionProvider { + + // 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 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 ImageDescriptor CHECKEDOUT_OVERLAY = Activator - .getDefault().getImageRegistry().getDescriptor( - Activator.ICON_CHECKEDOUT_OVR); + private final List<ISelectionChangedListener> selectionListeners = new ArrayList<ISelectionChangedListener>(); + + private ISelection currentSelection = new StructuredSelection(); private Job scheduledJob; @@ -127,196 +140,6 @@ public class RepositoriesView extends ViewPart { private IAction refreshAction; - enum RepositoryTreeNodeType { - - REPO(Activator.ICON_REPOSITORY), REF(PlatformUI.getWorkbench() - .getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER)), PROJ( - PlatformUI.getWorkbench().getSharedImages().getImage( - SharedImages.IMG_OBJ_PROJECT_CLOSED)), BRANCHES( - Activator.ICON_BRANCHES), PROJECTS(PlatformUI.getWorkbench() - .getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER)); - - private final Image myImage; - - private RepositoryTreeNodeType(String iconName) { - - if (iconName != null) { - myImage = Activator.getDefault().getImageRegistry().get( - iconName); - } else { - myImage = null; - } - - } - - private RepositoryTreeNodeType(Image icon) { - myImage = icon; - - } - - public Image getIcon() { - return myImage; - } - - } - - private static final class RepositoryTreeNode<T> { - - private final Repository myRepository; - - private final T myObject; - - private final RepositoryTreeNodeType myType; - - private final RepositoryTreeNode myParent; - - private String branch; - - public RepositoryTreeNode(RepositoryTreeNode parent, - RepositoryTreeNodeType type, Repository repository, T treeObject) { - myParent = parent; - myRepository = repository; - myType = type; - myObject = treeObject; - } - - @SuppressWarnings("unchecked") - private RepositoryTreeNode<Repository> getRepositoryNode() { - if (myType == RepositoryTreeNodeType.REPO) { - return (RepositoryTreeNode<Repository>) this; - } else { - return getParent().getRepositoryNode(); - } - } - - /** - * We keep this cached in the repository node to avoid repeated lookups - * - * @return the full branch - * @throws IOException - */ - public String getBranch() throws IOException { - if (myType != RepositoryTreeNodeType.REPO) { - return getRepositoryNode().getBranch(); - } - if (branch == null) { - branch = getRepository().getBranch(); - } - return branch; - } - - public RepositoryTreeNode getParent() { - return myParent; - } - - public RepositoryTreeNodeType getType() { - return myType; - } - - public Repository getRepository() { - return myRepository; - } - - public T getObject() { - return myObject; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - switch (myType) { - case REPO: - case PROJECTS: - case BRANCHES: - result = prime - * result - + ((myObject == null) ? 0 : ((Repository) myObject) - .getDirectory().hashCode()); - break; - case REF: - result = prime - * result - + ((myObject == null) ? 0 : ((Ref) myObject).getName() - .hashCode()); - break; - case PROJ: - result = prime - * result - + ((myObject == null) ? 0 : ((File) myObject).getPath() - .hashCode()); - break; - - default: - break; - } - - result = prime * result - + ((myParent == null) ? 0 : myParent.hashCode()); - result = prime - * result - + ((myRepository == null) ? 0 : myRepository.getDirectory() - .hashCode()); - result = prime * result - + ((myType == null) ? 0 : myType.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - - RepositoryTreeNode other = (RepositoryTreeNode) obj; - - if (myType == null) { - if (other.myType != null) - return false; - } else if (!myType.equals(other.myType)) - return false; - if (myParent == null) { - if (other.myParent != null) - return false; - } else if (!myParent.equals(other.myParent)) - return false; - if (myRepository == null) { - if (other.myRepository != null) - return false; - } else if (!myRepository.getDirectory().equals( - other.myRepository.getDirectory())) - return false; - if (myObject == null) { - if (other.myObject != null) - return false; - } else if (!checkObjectsEqual(other.myObject)) - return false; - - return true; - } - - private boolean checkObjectsEqual(Object otherObject) { - switch (myType) { - case REPO: - case PROJECTS: - case BRANCHES: - return ((Repository) myObject).getDirectory().equals( - ((Repository) otherObject).getDirectory()); - case REF: - return ((Ref) myObject).getName().equals( - ((Ref) otherObject).getName()); - case PROJ: - return ((File) myObject).getPath().equals( - ((File) otherObject).getPath()); - default: - return false; - } - } - } - private static final class ContentProvider implements ITreeContentProvider { @SuppressWarnings("unchecked") @@ -362,14 +185,29 @@ public class RepositoriesView extends ViewPart { List<RepositoryTreeNode<Ref>> refs = new ArrayList<RepositoryTreeNode<Ref>>(); - Repository rep = node.getRepository(); - for (Ref ref : rep.getAllRefs().values()) { + for (Ref ref : repo.getAllRefs().values()) { refs.add(new RepositoryTreeNode<Ref>(node, RepositoryTreeNodeType.REF, repo, ref)); } return refs.toArray(); + case REMOTES: + + List<RepositoryTreeNode<String>> remotes = new ArrayList<RepositoryTreeNode<String>>(); + + Repository rep = node.getRepository(); + + Set<String> configNames = rep.getConfig() + .getSubsections(REMOTE); + + for (String configName : configNames) { + remotes.add(new RepositoryTreeNode<String>(node, + RepositoryTreeNodeType.REMOTE, repo, configName)); + } + + return remotes.toArray(); + case REPO: List<RepositoryTreeNode<Repository>> branches = new ArrayList<RepositoryTreeNode<Repository>>(); @@ -382,6 +220,10 @@ public class RepositoriesView extends ViewPart { RepositoryTreeNodeType.PROJECTS, node.getRepository(), node.getRepository())); + branches.add(new RepositoryTreeNode<Repository>(node, + RepositoryTreeNodeType.REMOTES, node.getRepository(), + node.getRepository())); + return branches.toArray(); case PROJECTS: @@ -485,7 +327,7 @@ public class RepositoriesView extends ViewPart { private static final class LabelProvider extends BaseLabelProvider implements ITableLabelProvider { - private DefaultInformationControl infoControl; + // private DefaultInformationControl infoControl; /** * @@ -502,74 +344,75 @@ public class RepositoriesView extends ViewPart { @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); - - } + // 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); + // + // } } @@ -593,6 +436,15 @@ public class RepositoriesView extends ViewPart { .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: @@ -642,8 +494,9 @@ public class RepositoriesView extends ViewPart { protected void drawCompositeImage(int width, int height) { drawImage(image.getImageData(), 0, 0); - drawImage(CHECKEDOUT_OVERLAY.getImageData(), 0, - 0); + drawImage( + UIIcons.OVR_CHECKEDOUT.getImageData(), + 0, 0); } }; @@ -674,8 +527,9 @@ public class RepositoriesView extends ViewPart { protected void drawCompositeImage(int width, int height) { drawImage(image.getImageData(), 0, 0); - drawImage(CHECKEDOUT_OVERLAY.getImageData(), 0, - 0); + drawImage( + UIIcons.OVR_CHECKEDOUT.getImageData(), + 0, 0); } }; @@ -748,6 +602,15 @@ public class RepositoriesView extends ViewPart { @Override public Object getAdapter(Class adapter) { + + if (adapter == IPropertySheetPage.class) { + PropertySheetPage page = new PropertySheetPage(); + page + .setPropertySourceProvider(new RepositoryPropertySourceProvider( + page)); + return page; + } + return super.getAdapter(adapter); } @@ -755,6 +618,7 @@ public class RepositoriesView extends ViewPart { public void createPartControl(Composite parent) { Composite main = new Composite(parent, SWT.NONE); + main.setLayout(new GridLayout(1, false)); GridDataFactory.fillDefaults().grab(true, true).applyTo(main); main.setLayout(new GridLayout(1, false)); @@ -762,6 +626,23 @@ public class RepositoriesView extends ViewPart { tv.setContentProvider(new ContentProvider()); new LabelProvider(tv); + getSite().setSelectionProvider(this); + + tv.addSelectionChangedListener(new ISelectionChangedListener() { + + public void selectionChanged(SelectionChangedEvent event) { + + IStructuredSelection ssel = (IStructuredSelection) event + .getSelection(); + if (ssel.size() == 1) { + setSelection(new StructuredSelection(ssel.getFirstElement())); + } else { + setSelection(new StructuredSelection()); + } + + } + }); + GridDataFactory.fillDefaults().grab(true, true).applyTo(tv.getTree()); addContextMenu(); @@ -785,9 +666,6 @@ public class RepositoriesView extends ViewPart { addMenuItemsForPanel(men); } else { addMenuItemsForTreeSelection(men); - if (men.getItemCount() > 0) - new MenuItem(men, SWT.SEPARATOR); - addMenuItemsForPanel(men); } tv.getTree().setMenu(men); @@ -836,58 +714,17 @@ public class RepositoriesView extends ViewPart { @SuppressWarnings("unchecked") private void addMenuItemsForTreeSelection(Menu men) { - final List<RepositoryTreeNode<Ref>> refs = new ArrayList<RepositoryTreeNode<Ref>>(); - final List<RepositoryTreeNode<File>> projects = new ArrayList<RepositoryTreeNode<File>>(); - final List<RepositoryTreeNode<Repository>> repos = new ArrayList<RepositoryTreeNode<Repository>>(); - TreeItem[] selectedItems = tv.getTree().getSelection(); - for (TreeItem item : selectedItems) { - RepositoryTreeNode node = (RepositoryTreeNode) item.getData(); - switch (node.getType()) { - case PROJ: - projects.add(node); - break; - case REF: - refs.add(node); - break; - case REPO: - repos.add(node); - break; - default: - break; - } - } + final IStructuredSelection sel = (IStructuredSelection) tv + .getSelection(); - boolean importableProjectsOnly = !projects.isEmpty() && repos.isEmpty() - && refs.isEmpty(); + boolean importableProjectsOnly = true; - for (RepositoryTreeNode<File> prj : projects) { + for (Object node : sel.toArray()) { + RepositoryTreeNode tnode = (RepositoryTreeNode) node; + importableProjectsOnly = tnode.getType() == RepositoryTreeNodeType.PROJ; if (!importableProjectsOnly) break; - - for (IProject proj : ResourcesPlugin.getWorkspace().getRoot() - .getProjects()) { - if (proj.getLocation().equals( - new Path(prj.getObject().getAbsolutePath()))) - importableProjectsOnly = false; - - } - - } - - boolean singleRef = refs.size() == 1 && projects.isEmpty() - && repos.isEmpty(); - boolean singleRepo = repos.size() == 1 && projects.isEmpty() - && refs.isEmpty(); - - try { - singleRef = singleRef - && !refs.get(0).getObject().getName() - .equals(Constants.HEAD) - && (refs.get(0).getRepository().mapCommit( - refs.get(0).getObject().getLeaf().getObjectId()) != null); - } catch (IOException e2) { - singleRef = false; } if (importableProjectsOnly) { @@ -905,7 +742,8 @@ public class RepositoriesView extends ViewPart { public void run(IProgressMonitor monitor) throws CoreException { - for (RepositoryTreeNode<File> projectNode : projects) { + for (Object selected : sel.toArray()) { + RepositoryTreeNode<File> projectNode = (RepositoryTreeNode<File>) selected; File file = projectNode.getObject(); IProjectDescription pd = ResourcesPlugin @@ -954,7 +792,17 @@ public class RepositoriesView extends ViewPart { }); } - if (singleRef) { + // from here on, we only deal with single selection + if (sel.size() > 1) + return; + + final RepositoryTreeNode node = (RepositoryTreeNode) sel + .getFirstElement(); + + // for Refs (branches): checkout + if (node.getType() == RepositoryTreeNodeType.REF) { + + final Ref ref = (Ref) node.getObject(); MenuItem checkout = new MenuItem(men, SWT.PUSH); checkout @@ -963,8 +811,8 @@ public class RepositoriesView extends ViewPart { @Override public void widgetSelected(SelectionEvent e) { - Repository repo = refs.get(0).getRepository(); - String refName = refs.get(0).myObject.getLeaf().getName(); + Repository repo = node.getRepository(); + String refName = ref.getLeaf().getName(); final BranchOperation op = new BranchOperation(repo, refName); IWorkspaceRunnable wsr = new IWorkspaceRunnable() { @@ -993,7 +841,11 @@ public class RepositoriesView extends ViewPart { }); } - if (singleRepo) { + // for Repository: import existing projects, remove, (delete), open + // properties + if (node.getType() == RepositoryTreeNodeType.REPO) { + + final Repository repo = (Repository) node.getObject(); MenuItem importProjects = new MenuItem(men, SWT.PUSH); importProjects @@ -1002,32 +854,13 @@ public class RepositoriesView extends ViewPart { @Override public void widgetSelected(SelectionEvent e) { - Wizard wiz = new ExternalProjectImportWizard(repos.get(0) - .getRepository().getWorkDir().getAbsolutePath()) { + Wizard wiz = new ExternalProjectImportWizard(repo + .getWorkDir().getAbsolutePath()) { @Override public void addPages() { super.addPages(); // we could add some page with a single - // checkbox to indicate if we wan - // addPage(new WizardPage("Share") { - // - // public void createControl( - // Composite parent) { - // Composite main = new Composite( - // parent, SWT.NONE); - // main.setLayout(new GridLayout(1, - // false)); - // GridDataFactory.fillDefaults() - // .grab(true, true).applyTo( - // main); - // Button but = new Button(main, - // SWT.PUSH); - // but.setText("Push me"); - // setControl(main); - // - // } - // }); } @Override @@ -1052,10 +885,8 @@ public class RepositoriesView extends ViewPart { public void run(IProgressMonitor monitor) throws CoreException { - File gitDir = repos.get(0) - .getRepository().getDirectory(); - File gitWorkDir = repos.get(0) - .getRepository().getWorkDir(); + File gitDir = repo.getDirectory(); + File gitWorkDir = repo.getWorkDir(); Path workPath = new Path(gitWorkDir .getAbsolutePath()); @@ -1129,7 +960,7 @@ public class RepositoriesView extends ViewPart { public void widgetSelected(SelectionEvent e) { List<IProject> projectsToDelete = new ArrayList<IProject>(); - File workDir = repos.get(0).getRepository().getWorkDir(); + File workDir = repo.getWorkDir(); final IPath wdPath = new Path(workDir.getAbsolutePath()); for (IProject prj : ResourcesPlugin.getWorkspace() .getRoot().getProjects()) { @@ -1158,7 +989,6 @@ public class RepositoriesView extends ViewPart { } } - Repository repo = repos.get(0).getRepository(); removeDir(repo.getDirectory().getAbsolutePath()); scheduleRefresh(); } @@ -1278,6 +1108,140 @@ public class RepositoriesView extends ViewPart { // } // // }); + + MenuItem openPropsView = new MenuItem(men, SWT.PUSH); + openPropsView + .setText(RepositoryViewUITexts.RepositoriesView_OpenPropertiesMenu); + openPropsView.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + try { + PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().showView( + IPageLayout.ID_PROP_SHEET); + } catch (PartInitException e1) { + // just ignore + } + } + + }); + } + + if (node.getType() == RepositoryTreeNodeType.REMOTES) { + + MenuItem remoteConfig = new MenuItem(men, SWT.PUSH); + remoteConfig + .setText(RepositoryViewUITexts.RepositoriesView_NewRemoteMenu); + remoteConfig.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + new WizardDialog(getSite().getShell(), + new ConfigureRemoteWizard(node.getRepository())) + .open(); + scheduleRefresh(); + + } + + }); + } + + if (node.getType() == RepositoryTreeNodeType.REMOTE) { + + final String name = (String) node.getObject(); + + MenuItem configureUrlFetch = new MenuItem(men, SWT.PUSH); + configureUrlFetch + .setText(RepositoryViewUITexts.RepositoriesView_ConfigureFetchMenu); + configureUrlFetch.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + + new WizardDialog(getSite().getShell(), + new ConfigureRemoteWizard(node.getRepository(), + name, false)).open(); + scheduleRefresh(); + + } + + }); + + MenuItem configureUrlPush = new MenuItem(men, SWT.PUSH); + configureUrlPush + .setText(RepositoryViewUITexts.RepositoriesView_ConfigurePushMenu); + configureUrlPush.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + + new WizardDialog(getSite().getShell(), + new ConfigureRemoteWizard(node.getRepository(), + name, true)).open(); + scheduleRefresh(); + + } + + }); + + new MenuItem(men, SWT.SEPARATOR); + + MenuItem removeRemote = new MenuItem(men, SWT.PUSH); + removeRemote + .setText(RepositoryViewUITexts.RepositoriesView_RemoveRemoteMenu); + removeRemote.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + + boolean ok = MessageDialog + .openConfirm( + getSite().getShell(), + RepositoryViewUITexts.RepositoriesView_ConfirmDeleteRemoteHeader, + NLS + .bind( + RepositoryViewUITexts.RepositoriesView_ConfirmDeleteRemoteMessage, + name)); + if (ok) { + RepositoryConfig config = node.getRepository() + .getConfig(); + config.unsetSection(REMOTE, name); + try { + config.save(); + scheduleRefresh(); + } catch (IOException e1) { + MessageDialog + .openError( + getSite().getShell(), + RepositoryViewUITexts.RepositoriesView_ErrorHeader, + e1.getMessage()); + } + } + + } + + }); + + new MenuItem(men, SWT.SEPARATOR); + + MenuItem openPropsView = new MenuItem(men, SWT.PUSH); + openPropsView + .setText(RepositoryViewUITexts.RepositoriesView_OpenPropertiesMenu); + openPropsView.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + try { + PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().showView( + IPageLayout.ID_PROP_SHEET); + } catch (PartInitException e1) { + // just ignore + } + } + + }); } } @@ -1296,6 +1260,8 @@ public class RepositoriesView extends ViewPart { importAction .setToolTipText(RepositoryViewUITexts.RepositoriesView_Clone_Tooltip); + importAction.setImageDescriptor(UIIcons.IMPORT); + getViewSite().getActionBars().getToolBarManager().add(importAction); addAction = new Action( @@ -1320,6 +1286,8 @@ public class RepositoriesView extends ViewPart { addAction .setToolTipText(RepositoryViewUITexts.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 @@ -1333,6 +1301,8 @@ public class RepositoriesView extends ViewPart { } }; + refreshAction.setImageDescriptor(UIIcons.ELCL16_REFRESH); + getViewSite().getActionBars().getToolBarManager().add(refreshAction); } @@ -1376,6 +1346,16 @@ public class RepositoriesView extends ViewPart { Object selected = sel.getFirstElement(); if (selected != null) tv.reveal(selected); + + IViewPart part = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getActivePage() + .findView(IPageLayout.ID_PROP_SHEET); + if (part != null) { + PropertySheet sheet = (PropertySheet) part; + PropertySheetPage page = (PropertySheetPage) sheet + .getCurrentPage(); + page.refresh(); + } } }); @@ -1503,4 +1483,29 @@ public class RepositoriesView extends ViewPart { return confirmed; } + public void addSelectionChangedListener(ISelectionChangedListener listener) { + selectionListeners.add(listener); + } + + public ISelection getSelection() { + return currentSelection; + } + + public void removeSelectionChangedListener( + ISelectionChangedListener listener) { + selectionListeners.remove(listener); + + } + + public void setSelection(ISelection selection) { + currentSelection = selection; + for (ISelectionChangedListener listener : selectionListeners) { + listener.selectionChanged(new SelectionChangedEvent( + RepositoriesView.this, selection)); + } + } + + // private void showExceptionMessage(Exception e) { + // MessageDialog.openError(getSite().getShell(), "Error", e.getMessage()); + // } } 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 new file mode 100644 index 0000000000..f2360428a0 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySource.java @@ -0,0 +1,456 @@ +/******************************************************************************* + * 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.List; +import java.util.Set; +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.egit.core.Activator; +import org.eclipse.egit.ui.UIText; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.FileBasedConfig; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryConfig; +import org.eclipse.jgit.util.SystemReader; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.ui.views.properties.IPropertySource2; +import org.eclipse.ui.views.properties.PropertyDescriptor; +import org.eclipse.ui.views.properties.PropertySheetPage; +import org.eclipse.ui.views.properties.TextPropertyDescriptor; + +/** + * Properties for repository configuration + * + */ +public class RepositoryPropertySource implements IPropertySource, + IPropertySource2 { + + private static final String USER_ID_PREFIX = "user"; //$NON-NLS-1$ + + private static final String REPO_ID_PREFIX = "repo"; //$NON-NLS-1$ + + private static final String EFFECTIVE_ID_PREFIX = "effe"; //$NON-NLS-1$ + + private static final String PREFERENCE_KEYS = "RepositoryPropertySource.ConfiguredKeys"; //$NON-NLS-1$ + + private Action configureKeyAction; + + private Action modeToggleAction; + + private Action restoreKeyAction; + + private final PropertySheetPage myPage; + + private final FileBasedConfig userHomeConfig; + + private final FileBasedConfig repositoryConfig; + + private final RepositoryConfig effectiveConfig; + + /** + * @param rep + * the repository + * @param page + */ + public RepositoryPropertySource(Repository rep, PropertySheetPage page) { + + myPage = page; + + makeActions(); + addActions(); + + effectiveConfig = rep.getConfig(); + userHomeConfig = SystemReader.getInstance().openUserConfig(); + // TODO constant? + File configFile = new File(rep.getDirectory(), "config"); //$NON-NLS-1$ + repositoryConfig = new FileBasedConfig(configFile); + + try { + effectiveConfig.load(); + userHomeConfig.load(); + repositoryConfig.load(); + } catch (IOException e) { + // TODO refactor to a method and react on exceptions + e.printStackTrace(); + } catch (ConfigInvalidException e) { + // TODO refactor to a method and react on exceptions + e.printStackTrace(); + } + + } + + private void makeActions() { + + configureKeyAction = new Action( + UIText.RepositoryPropertySource_ConfigureKeysAction) { + + @Override + public String getId() { + return "ConfigKeyActionId"; //$NON-NLS-1$ + } + + @Override + public void run() { + ConfigureKeysDialog dlg = new ConfigureKeysDialog(myPage + .getSite().getShell(), getConfiguredKeys()); + if (dlg.open() == Window.OK) + try { + setConfiguredKeys(dlg.getActiveKeys()); + myPage.refresh(); + } catch (IOException e) { + showExceptionMessage(e); + } + + } + + }; + + modeToggleAction = new Action( + UIText.RepositoryPropertySource_EffectiveConfigurationAction) { + // TODO icon + @Override + public String getId() { + return "ViewModeToggle"; //$NON-NLS-1$ + } + + @Override + public void run() { + myPage.refresh(); + } + + @Override + public int getStyle() { + return IAction.AS_CHECK_BOX; + } + + }; + + restoreKeyAction = new Action( + UIText.RepositoryPropertySource_RestoreStandardAction) { + + @Override + public String getId() { + return "RestoreKeys"; //$NON-NLS-1$ + } + + @Override + public void run() { + try { + setConfiguredKeys(new ArrayList<String>()); + myPage.refresh(); + } catch (IOException e) { + showExceptionMessage(e); + } + } + + }; + } + + private void addActions() { + + boolean refreshToolbar = false; + IActionBars bars = myPage.getSite().getActionBars(); + + if (bars.getToolBarManager().find(modeToggleAction.getId()) == null) { + bars.getToolBarManager().add(modeToggleAction); + refreshToolbar = true; + } + + if (bars.getMenuManager().find(configureKeyAction.getId()) == null) + bars.getMenuManager().add(configureKeyAction); + + if (bars.getMenuManager().find(restoreKeyAction.getId()) == null) + bars.getMenuManager().add(restoreKeyAction); + + if (refreshToolbar) + bars.getToolBarManager().update(false); + } + + private List<String> getConfiguredKeys() { + + List<String> result = new ArrayList<String>(); + ScopedPreferenceStore store = new ScopedPreferenceStore( + new InstanceScope(), Activator.getPluginId()); + String keys = store.getString(PREFERENCE_KEYS); + if (keys.length() > 0) { + StringTokenizer tok = new StringTokenizer(keys, " "); //$NON-NLS-1$ + while (tok.hasMoreTokens()) { + result.add(tok.nextToken()); + } + } else { + result.addAll(ConfigureKeysDialog.standardKeys); + } + return result; + } + + private void setConfiguredKeys(List<String> keys) throws IOException { + + StringBuilder sb = new StringBuilder(); + for (String key : keys) { + sb.append(key); + sb.append(" "); //$NON-NLS-1$ + } + ScopedPreferenceStore store = new ScopedPreferenceStore( + new InstanceScope(), Activator.getPluginId()); + store.putValue(PREFERENCE_KEYS, sb.toString()); + store.save(); + + } + + private Object getValueFromConfig(Config config, String keyString) { + + StringTokenizer tok = new StringTokenizer(keyString, "."); //$NON-NLS-1$ + + String section; + String subsection; + String name; + + String[] valueList = null; + String value = null; + if (tok.countTokens() == 2) { + section = tok.nextToken(); + subsection = null; + name = tok.nextToken(); + } else if (tok.countTokens() == 3) { + section = tok.nextToken(); + subsection = tok.nextToken(); + name = tok.nextToken(); + } else { + // TODO exception? + 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) + return null; + + if (valueList.length == 1) { + return valueList[0]; + } + + return valueList; + + } + + public Object getEditableValue() { + return null; + } + + public IPropertyDescriptor[] getPropertyDescriptors() { + + // initFromConfig(); + + try { + userHomeConfig.load(); + repositoryConfig.load(); + effectiveConfig.load(); + } catch (IOException e) { + showExceptionMessage(e); + } catch (ConfigInvalidException e) { + showExceptionMessage(e); + } + + List<IPropertyDescriptor> resultList = new ArrayList<IPropertyDescriptor>(); + + List<String> configuredKeys = getConfiguredKeys(); + + boolean effectiveMode = false; + + ActionContributionItem item = (ActionContributionItem) myPage.getSite() + .getActionBars().getToolBarManager().find( + modeToggleAction.getId()); + if (item != null) { + effectiveMode = ((Action) item.getAction()).isChecked(); + } + + if (effectiveMode) { + for (String key : configuredKeys) { + + for (String sub : getSubSections(effectiveConfig, key)) { + PropertyDescriptor desc = new PropertyDescriptor( + EFFECTIVE_ID_PREFIX + sub, sub); + + desc + .setCategory(UIText.RepositoryPropertySource_EffectiveConfigurationCategory); + resultList.add(desc); + } + + } + } else { + + String categoryString = UIText.RepositoryPropertySource_GlobalConfigurationCategory + + userHomeConfig.getFile().getAbsolutePath(); + for (String key : configuredKeys) { + + // no remote configuration globally.... + if (key.startsWith(RepositoriesView.REMOTE + ".")) //$NON-NLS-1$ + continue; + + for (String sub : getSubSections(effectiveConfig, key)) { + TextPropertyDescriptor desc = new TextPropertyDescriptor( + USER_ID_PREFIX + sub, sub); + desc.setCategory(categoryString); + resultList.add(desc); + } + } + categoryString = UIText.RepositoryPropertySource_RepositoryConfigurationCategory + + repositoryConfig.getFile().getAbsolutePath(); + for (String key : configuredKeys) { + + for (String sub : getSubSections(effectiveConfig, key)) { + TextPropertyDescriptor desc = new TextPropertyDescriptor( + REPO_ID_PREFIX + sub, sub); + desc.setCategory(categoryString); + resultList.add(desc); + } + } + } + + return resultList.toArray(new IPropertyDescriptor[0]); + } + + private List<String> getSubSections(Config configuration, String key) { + + List<String> result = new ArrayList<String>(); + + if (key.indexOf(".?.") < 0) { //$NON-NLS-1$ + result.add(key); + return result; + } + + StringTokenizer stok = new StringTokenizer(key, "."); //$NON-NLS-1$ + if (stok.countTokens() == 3) { + String section = stok.nextToken(); + String subsection = stok.nextToken(); + String name = stok.nextToken(); + if (subsection.equals("?")) { //$NON-NLS-1$ + Set<String> subs = configuration.getSubsections(section); + for (String sub : subs) + result.add(section + "." + sub + "." + name); //$NON-NLS-1$ //$NON-NLS-2$ + return result; + } else { + result.add(key); + } + } + return result; + } + + public Object getPropertyValue(Object id) { + String actId = ((String) id); + Object value = null; + if (actId.startsWith(USER_ID_PREFIX)) { + value = getValueFromConfig(userHomeConfig, actId.substring(4)); + } else if (actId.startsWith(REPO_ID_PREFIX)) { + value = getValueFromConfig(repositoryConfig, actId.substring(4)); + } else if (actId.startsWith(EFFECTIVE_ID_PREFIX)) { + value = getValueFromConfig(effectiveConfig, actId.substring(4)); + } + if (value == null) + // the text editor needs this to work + return ""; //$NON-NLS-1$ + + return value; + } + + public boolean isPropertySet(Object id) { + String actId = ((String) id); + Object value = null; + if (actId.startsWith(USER_ID_PREFIX)) { + value = getValueFromConfig(userHomeConfig, actId.substring(4)); + } else if (actId.startsWith(REPO_ID_PREFIX)) { + value = getValueFromConfig(repositoryConfig, actId.substring(4)); + } else if (actId.startsWith(EFFECTIVE_ID_PREFIX)) { + value = getValueFromConfig(effectiveConfig, actId.substring(4)); + } + return value != null; + } + + public void resetPropertyValue(Object id) { + setPropertyValue(id, null); + } + + public void setPropertyValue(Object id, Object value) { + + String actId = (String) id; + try { + if (actId.startsWith(USER_ID_PREFIX)) { + setConfigValue(userHomeConfig, actId.substring(4), + (String) value); + } + if (actId.startsWith(REPO_ID_PREFIX)) { + setConfigValue(repositoryConfig, actId.substring(4), + (String) value); + } + } catch (IOException e) { + showExceptionMessage(e); + } + + } + + public boolean isPropertyResettable(Object id) { + return isPropertySet(id); + } + + private void setConfigValue(FileBasedConfig configuration, String key, + String value) throws IOException { + // we un-set empty strings, as the config API does not allow to + // distinguish this case + // (null is returned, even if the value is set to "", but in the + // effective configuration + // this results in shadowing of the base configured values + StringTokenizer tok = new StringTokenizer(key, "."); //$NON-NLS-1$ + if (tok.countTokens() == 2) { + if (value == null || value.length() == 0) { + configuration.unset(tok.nextToken(), null, tok.nextToken()); + } else { + configuration.setString(tok.nextToken(), null, tok.nextToken(), + value); + } + } + if (tok.countTokens() == 3) { + if (value == null || value.length() == 0) { + configuration.unset(tok.nextToken(), tok.nextToken(), tok + .nextToken()); + } else { + configuration.setString(tok.nextToken(), tok.nextToken(), tok + .nextToken(), value); + } + + } + configuration.save(); + } + + private void showExceptionMessage(Exception e) { + MessageDialog.openError(myPage.getSite().getShell(), + UIText.RepositoryPropertySource_ErrorHeader, e.getMessage()); + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySourceProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySourceProvider.java new file mode 100644 index 0000000000..06146a3f76 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryPropertySourceProvider.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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.egit.ui.internal.repository.RepositoryTreeNode.RepositoryTreeNodeType; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.ui.views.properties.IPropertySourceProvider; +import org.eclipse.ui.views.properties.PropertySheetPage; + +/** + * PropertySource provider for Resource properties + * + */ +public class RepositoryPropertySourceProvider implements + IPropertySourceProvider { + + private final PropertySheetPage myPage; + + private Object lastObject; + + private IPropertySource lastRepositorySource; + + /** + * @param page + * the page + */ + public RepositoryPropertySourceProvider(PropertySheetPage page) { + myPage = page; + } + + public IPropertySource getPropertySource(Object object) { + + if (object == lastObject) + return lastRepositorySource; + + if (!(object instanceof RepositoryTreeNode)) + return null; + + RepositoryTreeNode node = (RepositoryTreeNode) object; + + if (node.getType() == RepositoryTreeNodeType.REPO) { + lastObject = object; + lastRepositorySource = new RepositoryPropertySource( + (Repository) node.getObject(), myPage); + return lastRepositorySource; + } else if (node.getType() == RepositoryTreeNodeType.REMOTE) { + lastObject = object; + lastRepositorySource = new RepositoryRemotePropertySource(node + .getRepository().getConfig(), (String) node.getObject(), myPage); + return lastRepositorySource; + } else { + return null; + } + } +} 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 new file mode 100644 index 0000000000..164a3edba0 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryRemotePropertySource.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * 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.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.egit.ui.UIText; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lib.RepositoryConfig; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.ui.views.properties.PropertyDescriptor; +import org.eclipse.ui.views.properties.PropertySheetPage; + +/** + * Read-only view of remote configuration + */ +public class RepositoryRemotePropertySource implements IPropertySource { + + private final RepositoryConfig myConfig; + + private final String myName; + + private final PropertySheetPage myPage; + + /** + * @param config + * @param remoteName + * @param page + * + */ + public RepositoryRemotePropertySource(RepositoryConfig config, + String remoteName, PropertySheetPage page) { + myConfig = config; + myName = remoteName; + myPage = page; + } + + public Object getEditableValue() { + return null; + } + + public IPropertyDescriptor[] getPropertyDescriptors() { + + try { + myConfig.load(); + } catch (IOException e) { + showExceptionMessage(e); + } catch (ConfigInvalidException e) { + showExceptionMessage(e); + } + List<IPropertyDescriptor> resultList = new ArrayList<IPropertyDescriptor>(); + PropertyDescriptor desc = new PropertyDescriptor(RepositoriesView.URL, + UIText.RepositoryRemotePropertySource_RemoteUrlLabel); + resultList.add(desc); + desc = new PropertyDescriptor(RepositoriesView.FETCH, + UIText.RepositoryRemotePropertySource_FetchLabel); + resultList.add(desc); + desc = new PropertyDescriptor(RepositoriesView.PUSH, + UIText.RepositoryRemotePropertySource_PushLabel); + resultList.add(desc); + return resultList.toArray(new IPropertyDescriptor[resultList.size()]); + } + + public Object getPropertyValue(Object id) { + String[] list = myConfig.getStringList(RepositoriesView.REMOTE, myName, + (String) id); + if (list != null && list.length > 1) { + // let's show this as "[some/uri][another/uri]" + StringBuffer sb = new StringBuffer(); + for (String s : list) { + sb.append('['); + sb.append(s); + sb.append(']'); + } + return sb.toString(); + } + return myConfig.getString(RepositoriesView.REMOTE, myName, (String) id); + } + + public boolean isPropertySet(Object id) { + // no default values + return false; + } + + public void resetPropertyValue(Object id) { + // nothing to do + } + + public void setPropertyValue(Object id, Object value) { + // read-only + } + + private void showExceptionMessage(Exception e) { + MessageDialog.openError(myPage.getSite().getShell(), + UIText.RepositoryRemotePropertySource_ErrorHeader, e + .getMessage()); + } +} 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 2b18e5351d..d9a3e47fd2 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 @@ -18,6 +18,7 @@ import java.util.Set; import java.util.TreeSet; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.egit.ui.UIText; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; @@ -49,7 +50,6 @@ import org.eclipse.swt.widgets.Text; /** * Searches for Git directories under a path that can be selected by the user - * TODO String externalization */ public class RepositorySearchDialog extends Dialog { @@ -127,7 +127,7 @@ public class RepositorySearchDialog extends Dialog { @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); - newShell.setText("Search Git Repositories"); + newShell.setText(UIText.RepositorySearchDialog_SearchRepositoriesHeader); } @Override @@ -149,7 +149,7 @@ public class RepositorySearchDialog extends Dialog { GridDataFactory.fillDefaults().grab(true, true).applyTo(main); Label dirLabel = new Label(main, SWT.NONE); - dirLabel.setText("Directory"); + dirLabel.setText(UIText.RepositorySearchDialog_DirectoryLabel); final Text dir = new Text(main, SWT.NONE); if (myInitialPath != null) dir.setText(myInitialPath); @@ -158,7 +158,7 @@ public class RepositorySearchDialog extends Dialog { false).applyTo(dir); Button browse = new Button(main, SWT.PUSH); - browse.setText("Browse..."); + browse.setText(UIText.RepositorySearchDialog_BrowseButton); browse.addSelectionListener(new SelectionAdapter() { @Override @@ -174,7 +174,7 @@ public class RepositorySearchDialog extends Dialog { }); Button search = new Button(main, SWT.PUSH); - search.setText("Search"); + search.setText(UIText.RepositorySearchDialog_SearchButton); GridDataFactory.fillDefaults().align(SWT.LEAD, SWT.CENTER).span(3, 1) .applyTo(search); @@ -217,7 +217,7 @@ public class RepositorySearchDialog extends Dialog { pd.run(true, true, action); } catch (InvocationTargetException e1) { - MessageDialog.openError(getShell(), "Error", e1 + MessageDialog.openError(getShell(), UIText.RepositorySearchDialog_ErrorHeader, e1 .getCause().getMessage()); } catch (InterruptedException e1) { // ignore 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 new file mode 100644 index 0000000000..c0487fe7bc --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNode.java @@ -0,0 +1,275 @@ +/******************************************************************************* + * 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.egit.ui.Activator; +import org.eclipse.egit.ui.UIIcons; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE.SharedImages; + +/** + * A node in the Git Repositories view tree + * + * @param <T> + * the type + */ +class RepositoryTreeNode<T> { + + private final Repository myRepository; + + private final T myObject; + + private final RepositoryTreeNodeType myType; + + private final RepositoryTreeNode myParent; + + private String branch; + + RepositoryTreeNode(RepositoryTreeNode parent, RepositoryTreeNodeType type, + Repository repository, T treeObject) { + myParent = parent; + myRepository = repository; + myType = type; + myObject = treeObject; + } + + @SuppressWarnings("unchecked") + private RepositoryTreeNode<Repository> getRepositoryNode() { + if (myType == RepositoryTreeNodeType.REPO) { + return (RepositoryTreeNode<Repository>) this; + } else { + return getParent().getRepositoryNode(); + } + } + + /** + * We keep this cached in the repository node to avoid repeated lookups + * + * @return the full branch + * @throws IOException + */ + public String getBranch() throws IOException { + if (myType != RepositoryTreeNodeType.REPO) { + return getRepositoryNode().getBranch(); + } + if (branch == null) { + branch = getRepository().getBranch(); + } + return branch; + } + + /** + * @return the parent, or null + */ + public RepositoryTreeNode getParent() { + return myParent; + } + + /** + * @return the type + */ + public RepositoryTreeNodeType getType() { + return myType; + } + + /** + * @return the repository + */ + public Repository getRepository() { + return myRepository; + } + + /** + * Depending on the node type, the returned type is: + * + * <table border=1> + * <th>Type</th> + * <th>Object type</th> + * <tr> + * <td>{@link RepositoryTreeNodeType#BRANCHES}</td> + * <td>{@link String}</td> + * </tr> + * <tr> + * <td>{@link RepositoryTreeNodeType#PROJ}</td> + * <td>{@link File}</td> + * </tr> + * <tr> + * <td>{@link RepositoryTreeNodeType#PROJECTS}</td> + * <td>{@link String}</td> + * </tr> + * <tr> + * <td>{@link RepositoryTreeNodeType#REF}</td> + * <td>{@link Ref}</td> + * </tr> + * <tr> + * <td>{@link RepositoryTreeNodeType#REMOTE}</td> + * <td>{@link String}</td> + * </tr> + * <tr> + * <td>{@link RepositoryTreeNodeType#REMOTES}</td> + * <td>{@link String}</td> + * </tr> + * <tr> + * <td>{@link RepositoryTreeNodeType#REPO}</td> + * <td>{@link Repository}</td> + * </tr> + * </table> + * + * @return the type-specific object + */ + public T getObject() { + return myObject; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + switch (myType) { + case REPO: + case PROJECTS: + case BRANCHES: + result = prime + * result + + ((myObject == null) ? 0 : ((Repository) myObject) + .getDirectory().hashCode()); + break; + case REF: + result = prime + * result + + ((myObject == null) ? 0 : ((Ref) myObject).getName() + .hashCode()); + break; + case PROJ: + result = prime + * result + + ((myObject == null) ? 0 : ((File) myObject).getPath() + .hashCode()); + break; + + default: + break; + } + + result = prime * result + + ((myParent == null) ? 0 : myParent.hashCode()); + result = prime + * result + + ((myRepository == null) ? 0 : myRepository.getDirectory() + .hashCode()); + result = prime * result + ((myType == null) ? 0 : myType.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + + RepositoryTreeNode other = (RepositoryTreeNode) obj; + + if (myType == null) { + if (other.myType != null) + return false; + } else if (!myType.equals(other.myType)) + return false; + if (myParent == null) { + if (other.myParent != null) + return false; + } else if (!myParent.equals(other.myParent)) + return false; + if (myRepository == null) { + if (other.myRepository != null) + return false; + } else if (!myRepository.getDirectory().equals( + other.myRepository.getDirectory())) + return false; + if (myObject == null) { + if (other.myObject != null) + return false; + } else if (!checkObjectsEqual(other.myObject)) + return false; + + return true; + } + + private boolean checkObjectsEqual(Object otherObject) { + switch (myType) { + case REPO: + case PROJECTS: + case REMOTES: + case BRANCHES: + return ((Repository) myObject).getDirectory().equals( + ((Repository) otherObject).getDirectory()); + case REF: + return ((Ref) myObject).getName().equals( + ((Ref) otherObject).getName()); + case PROJ: + return ((File) myObject).getPath().equals( + ((File) otherObject).getPath()); + case REMOTE: + return myObject.equals(otherObject); + } + return false; + } + + enum RepositoryTreeNodeType { + + REPO(UIIcons.REPOSITORY.createImage()), // + REF(PlatformUI.getWorkbench().getSharedImages().getImage( + ISharedImages.IMG_OBJ_FOLDER)), // + PROJ(PlatformUI.getWorkbench().getSharedImages().getImage( + SharedImages.IMG_OBJ_PROJECT_CLOSED)), // + BRANCHES(UIIcons.BRANCHES.createImage()), // + PROJECTS(PlatformUI.getWorkbench().getSharedImages().getImage( + ISharedImages.IMG_OBJ_FOLDER)), // + REMOTES(UIIcons.REMOTE_REPOSITORY.createImage()), // + REMOTE(PlatformUI.getWorkbench().getSharedImages().getImage( + ISharedImages.IMG_OBJ_FOLDER)) + + ; + + private final Image myImage; + + private RepositoryTreeNodeType(String iconName) { + + if (iconName != null) { + myImage = Activator.getDefault().getImageRegistry().get( + iconName); + } else { + myImage = null; + } + + } + + private RepositoryTreeNodeType(Image icon) { + myImage = icon; + + } + + public Image getIcon() { + return myImage; + } + + } + +} 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 index 0322cc7012..fb8a9e2dd9 100644 --- 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 @@ -1,6 +1,17 @@ +/******************************************************************************* + * 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 * @@ -33,6 +44,18 @@ public class RepositoryViewUITexts extends NLS { 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; /** */ @@ -42,6 +65,9 @@ public class RepositoryViewUITexts extends NLS { public static String RepositoriesView_Error_WindowTitle; /** */ + public static String RepositoriesView_ErrorHeader; + + /** */ public static String RepositoriesView_ExistingProjects_Nodetext; /** */ @@ -57,16 +83,26 @@ public class RepositoryViewUITexts extends NLS { 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); } - private RepositoryViewUITexts() { - } } 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 new file mode 100644 index 0000000000..4ebc6e9555 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/SelectRemoteNamePage.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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.egit.ui.UIText; +import org.eclipse.jface.layout.GridDataFactory; +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.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** + * + */ +public class SelectRemoteNamePage extends WizardPage { + + Text remoteName; + + /** + * + */ + SelectRemoteNamePage() { + super(SelectRemoteNamePage.class.getName()); + setTitle(UIText.SelectRemoteNamePage_RemoteNameTitle); + setMessage(UIText.SelectRemoteNamePage_RemoteNameMessage); + } + + public void createControl(Composite parent) { + + setMessage(UIText.SelectRemoteNamePage_SelectRemoteNameMessage); + + Composite main = new Composite(parent, SWT.NONE); + + main.setLayout(new GridLayout(2, false)); + GridDataFactory.fillDefaults().grab(true, true).applyTo(main); + Label nameLabel = new Label(main, SWT.NONE); + nameLabel.setText(UIText.SelectRemoteNamePage_RemoteNameLabel); + + remoteName = new Text(main, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).applyTo(remoteName); + remoteName.addModifyListener(new ModifyListener() { + + public void modifyText(ModifyEvent e) { + checkPage(); + } + }); + + setControl(main); + setPageComplete(false); + + } + + private void checkPage() { + try { + setErrorMessage(null); + if (remoteName.getText().equals("")) { //$NON-NLS-1$ + setErrorMessage(UIText.SelectRemoteNamePage_NameMustNotBeEmptyMessage); + return; + } + + ConfigureRemoteWizard wizard = (ConfigureRemoteWizard) getWizard(); + if (wizard.getConfiguration().getSubsections( + RepositoriesView.REMOTE).contains(remoteName.getText())) { + setErrorMessage(UIText.SelectRemoteNamePage_NameInUseMessage); + 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 index e8e369c789..df3161a54b 100644 --- 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 @@ -6,13 +6,22 @@ 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 b2aca2a7ea..78139e0f9f 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 @@ -25,6 +25,12 @@ WizardProjectsImportPage_CreateProjectsTask = Creating Projects WizardProjectsImportPage_enableGit = Enable &Git Team operations on imported projects WizardProjectsImportPage_filterText = type filter text to filter unselected projects +SelectRemoteNamePage_NameInUseMessage=Remote name already in use +SelectRemoteNamePage_NameMustNotBeEmptyMessage=The remote name must not be empty +SelectRemoteNamePage_RemoteNameLabel=Remote name +SelectRemoteNamePage_RemoteNameMessage=Please select a remote name +SelectRemoteNamePage_RemoteNameTitle=Remote Name +SelectRemoteNamePage_SelectRemoteNameMessage=Select a remote name SharingWizard_windowTitle=Configure Git Repository SharingWizard_failed=Failed to initialize Git team provider. @@ -58,6 +64,22 @@ GitProjectPropertyPage_LabelWorkdir=Working directory: GitProjectPropertyPage_ValueEmptyRepository=None (empty repository) GitProjectPropertyPage_ValueUnbornBranch=None (unborn branch) +RepositoryPropertySource_ConfigureKeysAction=Configure Keys... +RepositoryPropertySource_EffectiveConfigurationAction=Effective Configuration +RepositoryPropertySource_EffectiveConfigurationCategory=Effective configuration +RepositoryPropertySource_ErrorHeader=Error +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 +RepositorySearchDialog_BrowseButton=Browse... +RepositorySearchDialog_DirectoryLabel=Directory +RepositorySearchDialog_ErrorHeader=Error +RepositorySearchDialog_SearchButton=Search +RepositorySearchDialog_SearchRepositoriesHeader=Search Git Repositories RepositorySelectionPage_BrowseLocalFile=Local file... RepositorySelectionPage_sourceSelectionTitle=Source Git Repository RepositorySelectionPage_sourceSelectionDescription=Enter the location of the source repository. @@ -258,6 +280,14 @@ CommitDialog_StatusModifiedNotStaged=Mod., not staged CommitDialog_StatusRemoved=Removed CommitDialog_StatusRemovedNotStaged=Rem., not staged CommitDialog_StatusUnknown=Unknown +ConfigureKeysDialog_AddStandardButton=Add standard keys +ConfigureKeysDialog_AlreadyThere_Message=Key {0} is alredy in the list +ConfigureKeysDialog_DeleteButton=Delete +ConfigureKeysDialog_DialogTitle=Select Git configuration keys to display in the Properties view +ConfigureKeysDialog_NewButton=New... +ConfigureKeysDialog_NewKeyLabel=New key +ConfigureRemoteWizard_WizardTitle_Change=Change remote configuration {0} +ConfigureRemoteWizard_WizardTitle_New=Create a new remote configuration ConfirmationPage_cantConnectToAnyTitle=Can't Connect ConfirmationPage_cantConnectToAny=Can't connect to any URI: {0} ConfirmationPage_description=Confirm following expected push result. |