1 /*******************************************************************************
2 * Copyright (C) 2007, 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
4 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
6 * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
7 * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
9 * All rights reserved. This program and the accompanying materials
10 * are made available under the terms of the Eclipse Public License v1.0
11 * which accompanies this distribution, and is available at
12 * http://www.eclipse.org/legal/epl-v10.html
13 *******************************************************************************/
14 package org
.eclipse
.egit
.ui
.internal
.components
;
17 import java
.net
.URISyntaxException
;
18 import java
.util
.ArrayList
;
19 import java
.util
.List
;
20 import java
.util
.TreeMap
;
21 import java
.util
.regex
.Pattern
;
23 import org
.eclipse
.egit
.core
.RepositoryUtil
;
24 import org
.eclipse
.egit
.core
.securestorage
.UserPasswordCredentials
;
25 import org
.eclipse
.egit
.ui
.Activator
;
26 import org
.eclipse
.egit
.ui
.UIPreferences
;
27 import org
.eclipse
.egit
.ui
.UIUtils
;
28 import org
.eclipse
.egit
.ui
.UIUtils
.IPreviousValueProposalHandler
;
29 import org
.eclipse
.egit
.ui
.internal
.SecureStoreUtils
;
30 import org
.eclipse
.egit
.ui
.internal
.UIText
;
31 import org
.eclipse
.egit
.ui
.internal
.clone
.GitUrlChecker
;
32 import org
.eclipse
.egit
.ui
.internal
.components
.RemoteSelectionCombo
.IRemoteSelectionListener
;
33 import org
.eclipse
.egit
.ui
.internal
.components
.RemoteSelectionCombo
.SelectionType
;
34 import org
.eclipse
.egit
.ui
.internal
.provisional
.wizards
.GitRepositoryInfo
;
35 import org
.eclipse
.egit
.ui
.internal
.provisional
.wizards
.IRepositorySearchResult
;
36 import org
.eclipse
.jface
.dialogs
.Dialog
;
37 import org
.eclipse
.jface
.layout
.GridDataFactory
;
38 import org
.eclipse
.jface
.preference
.IPreferenceStore
;
39 import org
.eclipse
.jface
.wizard
.WizardPage
;
40 import org
.eclipse
.jgit
.lib
.Constants
;
41 import org
.eclipse
.jgit
.transport
.RemoteConfig
;
42 import org
.eclipse
.jgit
.transport
.URIish
;
43 import org
.eclipse
.jgit
.util
.FS
;
44 import org
.eclipse
.osgi
.util
.NLS
;
45 import org
.eclipse
.swt
.SWT
;
46 import org
.eclipse
.swt
.dnd
.Clipboard
;
47 import org
.eclipse
.swt
.dnd
.TextTransfer
;
48 import org
.eclipse
.swt
.events
.ModifyEvent
;
49 import org
.eclipse
.swt
.events
.ModifyListener
;
50 import org
.eclipse
.swt
.events
.SelectionAdapter
;
51 import org
.eclipse
.swt
.events
.SelectionEvent
;
52 import org
.eclipse
.swt
.events
.SelectionListener
;
53 import org
.eclipse
.swt
.events
.VerifyEvent
;
54 import org
.eclipse
.swt
.events
.VerifyListener
;
55 import org
.eclipse
.swt
.layout
.GridData
;
56 import org
.eclipse
.swt
.layout
.GridLayout
;
57 import org
.eclipse
.swt
.widgets
.Button
;
58 import org
.eclipse
.swt
.widgets
.Combo
;
59 import org
.eclipse
.swt
.widgets
.Composite
;
60 import org
.eclipse
.swt
.widgets
.DirectoryDialog
;
61 import org
.eclipse
.swt
.widgets
.Display
;
62 import org
.eclipse
.swt
.widgets
.Event
;
63 import org
.eclipse
.swt
.widgets
.Group
;
64 import org
.eclipse
.swt
.widgets
.Label
;
65 import org
.eclipse
.swt
.widgets
.Text
;
66 import org
.eclipse
.ui
.PlatformUI
;
69 * Wizard page that allows the user entering the location of a remote repository
70 * by specifying URL manually or selecting a preconfigured remote repository.
72 public class RepositorySelectionPage
extends WizardPage
implements IRepositorySearchResult
{
74 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
76 private final static String USED_URIS_PREF
= "RepositorySelectionPage.UsedUris"; //$NON-NLS-1$
78 private final List
<RemoteConfig
> configuredRemotes
;
80 private final boolean sourceSelection
;
82 private final String presetUri
;
84 private Group authGroup
;
88 private Text hostText
;
90 private Text pathText
;
92 private Text userText
;
94 private Text passText
;
96 private Button storeCheckbox
;
100 private Text portText
;
102 private int eventDepth
;
106 private RemoteConfig remoteConfig
;
108 private RepositorySelection selection
;
110 private Composite remotePanel
;
112 private Button remoteButton
;
114 private RemoteSelectionCombo remoteCombo
;
116 private Composite uriPanel
;
118 private Button uriButton
;
120 private IPreviousValueProposalHandler uriProposalHandler
;
122 private String user
= EMPTY_STRING
;
124 private String password
= EMPTY_STRING
;
126 private boolean storeInSecureStore
;
128 private String helpContext
= null;
131 * Transport protocol abstraction
133 * TODO rework this to become part of JGit API
135 public static class Protocol
{
136 /** Ordered list of all protocols **/
137 private static final TreeMap
<String
, Protocol
> protocols
= new TreeMap
<>();
139 /** Git native transfer */
140 public static final Protocol GIT
= new Protocol("git", //$NON-NLS-1$
141 UIText
.RepositorySelectionPage_tip_git
, true, true, false);
144 public static final Protocol SSH
= new Protocol("ssh", //$NON-NLS-1$
145 UIText
.RepositorySelectionPage_tip_ssh
, true, true, true) {
147 public boolean handles(URIish uri
) {
150 final String scheme
= uri
.getScheme();
151 if (getDefaultScheme().equals(scheme
))
153 if ("ssh+git".equals(scheme
)) //$NON-NLS-1$
155 if ("git+ssh".equals(scheme
)) //$NON-NLS-1$
157 if (scheme
== null && uri
.getHost() != null
158 && uri
.getPath() != null)
165 public static final Protocol SFTP
= new Protocol("sftp", //$NON-NLS-1$
166 UIText
.RepositorySelectionPage_tip_sftp
, true, true, true);
169 public static final Protocol HTTP
= new Protocol("http", //$NON-NLS-1$
170 UIText
.RepositorySelectionPage_tip_http
, true, true, true);
173 public static final Protocol HTTPS
= new Protocol("https", //$NON-NLS-1$
174 UIText
.RepositorySelectionPage_tip_https
, true, true, true);
177 public static final Protocol FTP
= new Protocol("ftp", //$NON-NLS-1$
178 UIText
.RepositorySelectionPage_tip_ftp
, true, true, true);
180 /** Local repository */
181 public static final Protocol FILE
= new Protocol("file", //$NON-NLS-1$
182 UIText
.RepositorySelectionPage_tip_file
, false, false, false) {
184 public boolean handles(URIish uri
) {
185 if (getDefaultScheme().equals(uri
.getScheme()))
187 if (uri
.getHost() != null || uri
.getPort() > 0
188 || uri
.getUser() != null || uri
.getPass() != null
189 || uri
.getPath() == null)
191 if (uri
.getScheme() == null)
193 .resolve(new File("."), uri
.getPath()).isDirectory(); //$NON-NLS-1$
198 private final String defaultScheme
;
200 private final String tooltip
;
202 private final boolean hasHost
;
204 private final boolean hasPort
;
206 private final boolean canAuthenticate
;
208 private Protocol(String defaultScheme
, String tooltip
,
209 boolean hasHost
, boolean hasPort
, boolean canAuthenticate
) {
210 this.defaultScheme
= defaultScheme
;
211 this.tooltip
= tooltip
;
212 this.hasHost
= hasHost
;
213 this.hasPort
= hasPort
;
214 this.canAuthenticate
= canAuthenticate
;
215 protocols
.put(defaultScheme
, this);
220 * URI to match against this protocol
221 * @return {@code true} if the uri is handled by this protocol
223 public boolean handles(URIish uri
) {
224 return getDefaultScheme().equals(uri
.getScheme());
228 * @return the default protocol scheme
230 public String
getDefaultScheme() {
231 return defaultScheme
;
235 * @return the tooltip text describing the protocol
237 public String
getTooltip() {
242 * @return true if protocol has host segment
244 public boolean hasHost() {
249 * @return true if protocol has port
251 public boolean hasPort() {
256 * @return true if protocol can authenticate
258 public boolean canAuthenticate() {
259 return canAuthenticate
;
263 * @return all protocols
265 public static Protocol
[] values() {
266 return protocols
.values().toArray(new Protocol
[protocols
.size()]);
270 * Lookup protocol supporting given default URL scheme
273 * default scheme to lookup protocol for
274 * @return protocol matching scheme or null
276 public static Protocol
fromDefaultScheme(String scheme
) {
277 return protocols
.get(scheme
);
281 * Lookup protocol handling given URI
283 * @param uri URI to lookup protocol for
284 * @return protocol handling this URI
286 public static Protocol
fromUri(URIish uri
) {
287 for (Protocol p
: protocols
.values())
295 * Create repository selection page, allowing user specifying URI or
296 * (optionally) choosing from preconfigured remotes list.
298 * Wizard page is created without image, just with text description.
300 * @param sourceSelection
301 * true if dialog is used for source selection; false otherwise
302 * (destination selection). This indicates appropriate text
304 * @param configuredRemotes
305 * list of configured remotes that user may select as an
306 * alternative to manual URI specification. Remotes appear in
307 * given order in GUI, with
308 * {@value Constants#DEFAULT_REMOTE_NAME} as the default choice.
309 * List may be null or empty - no remotes configurations appear
310 * in this case. Note that the provided list may be changed by
313 * the pre-set URI, may be null
315 public RepositorySelectionPage(final boolean sourceSelection
,
316 final List
<RemoteConfig
> configuredRemotes
, String presetUri
) {
318 super(RepositorySelectionPage
.class.getName());
320 this.uri
= new URIish();
321 this.sourceSelection
= sourceSelection
;
323 String preset
= presetUri
;
324 if (presetUri
== null) {
325 Clipboard clipboard
= new Clipboard(Display
.getCurrent());
326 String text
= (String
) clipboard
327 .getContents(TextTransfer
.getInstance());
329 text
= GitUrlChecker
.sanitizeAsGitUrl(text
);
330 if (GitUrlChecker
.isValidGitUrl(text
)) {
336 this.presetUri
= preset
;
338 this.configuredRemotes
= getUsableConfigs(configuredRemotes
);
340 selection
= RepositorySelection
.INVALID_SELECTION
;
342 if (sourceSelection
) {
343 setTitle(UIText
.RepositorySelectionPage_sourceSelectionTitle
);
344 setDescription(UIText
.RepositorySelectionPage_sourceSelectionDescription
);
346 setTitle(UIText
.RepositorySelectionPage_destinationSelectionTitle
);
347 setDescription(UIText
.RepositorySelectionPage_destinationSelectionDescription
);
350 storeInSecureStore
= getPreferenceStore().getBoolean(
351 UIPreferences
.CLONE_WIZARD_STORE_SECURESTORE
);
355 * Create repository selection page, allowing user specifying URI, with no
356 * preconfigured remotes selection.
358 * @param sourceSelection
359 * true if dialog is used for source selection; false otherwise
360 * (destination selection). This indicates appropriate text
363 * the pre-set URI, may be null
365 public RepositorySelectionPage(final boolean sourceSelection
,
367 this(sourceSelection
, null, presetUri
);
371 * No args constructor; needed because the page is provided by the extension
372 * point {@code org.eclipse.egit.ui.cloneSourceProvider}
374 public RepositorySelectionPage() {
379 * @return repository selection representing current page state.
381 public RepositorySelection
getSelection() {
386 * Compare current repository selection set by user to provided one.
389 * repository selection to compare.
390 * @return true if provided selection is equal to current page selection,
393 public boolean selectionEquals(final RepositorySelection s
) {
394 return selection
.equals(s
);
398 public void createControl(final Composite parent
) {
399 final Composite panel
= new Composite(parent
, SWT
.NULL
);
400 panel
.setLayout(new GridLayout());
402 if (configuredRemotes
!= null)
403 createRemotePanel(panel
);
405 createRemoteNamePanel(panel
);
407 createUriPanel(panel
);
409 if (presetUri
!= null)
410 updateFields(presetUri
);
412 updateRemoteAndURIPanels();
413 Dialog
.applyDialogFont(panel
);
419 private void createRemotePanel(final Composite parent
) {
420 remoteButton
= new Button(parent
, SWT
.RADIO
);
422 .setText(UIText
.RepositorySelectionPage_configuredRemoteChoice
423 + ":"); //$NON-NLS-1$
424 remoteButton
.setSelection(true);
426 remotePanel
= new Composite(parent
, SWT
.NULL
);
427 remotePanel
.setLayout(new GridLayout());
428 final GridData gd
= new GridData();
429 gd
.grabExcessHorizontalSpace
= true;
430 gd
.horizontalAlignment
= SWT
.FILL
;
431 remotePanel
.setLayoutData(gd
);
433 SelectionType selectionType
= sourceSelection ? SelectionType
.FETCH
: SelectionType
.PUSH
;
434 remoteCombo
= new RemoteSelectionCombo(remotePanel
, SWT
.NULL
, selectionType
);
435 remoteConfig
= remoteCombo
.setItems(configuredRemotes
);
436 remoteCombo
.addRemoteSelectionListener(new IRemoteSelectionListener() {
438 public void remoteSelected(RemoteConfig rc
) {
449 protected void createRemoteNamePanel(Composite panel
) {
450 // Only used by subclass
453 private void createUriPanel(final Composite parent
) {
454 if (configuredRemotes
!= null) {
455 uriButton
= new Button(parent
, SWT
.RADIO
);
456 uriButton
.setText(UIText
.RepositorySelectionPage_uriChoice
+ ":"); //$NON-NLS-1$
457 uriButton
.addSelectionListener(new SelectionAdapter() {
459 public void widgetSelected(SelectionEvent e
) {
460 // occurs either on selection or unselection event
461 updateRemoteAndURIPanels();
467 uriPanel
= new Composite(parent
, SWT
.NULL
);
468 uriPanel
.setLayout(new GridLayout());
469 final GridData gd
= new GridData();
470 gd
.grabExcessHorizontalSpace
= true;
471 gd
.horizontalAlignment
= SWT
.FILL
;
472 uriPanel
.setLayoutData(gd
);
474 createLocationGroup(uriPanel
);
475 createConnectionGroup(uriPanel
);
476 authGroup
= createAuthenticationGroup(uriPanel
);
479 private void createLocationGroup(final Composite parent
) {
480 final Group g
= createGroup(parent
,
481 UIText
.RepositorySelectionPage_groupLocation
);
483 g
.setLayout(new GridLayout(3, false));
485 newLabel(g
, UIText
.RepositorySelectionPage_promptURI
+ ":"); //$NON-NLS-1$
486 uriText
= new Text(g
, SWT
.BORDER
);
488 if (presetUri
!= null) {
489 uriText
.setText(presetUri
);
493 uriText
.setLayoutData(createFieldGridData());
494 uriText
.addModifyListener(new ModifyListener() {
496 public void modifyText(final ModifyEvent e
) {
497 updateFields(uriText
.getText());
501 uriProposalHandler
= UIUtils
.addPreviousValuesContentProposalToText(
502 uriText
, USED_URIS_PREF
);
504 Button browseButton
= new Button(g
, SWT
.NULL
);
505 browseButton
.setText(UIText
.RepositorySelectionPage_BrowseLocalFile
);
506 browseButton
.addSelectionListener(new SelectionAdapter() {
509 public void widgetSelected(SelectionEvent evt
) {
510 DirectoryDialog dialog
= new DirectoryDialog(getShell());
511 if (sourceSelection
) {
513 UIText
.RepositorySelectionPage_sourceSelectionTitle
);
516 UIText
.RepositorySelectionPage_destinationSelectionTitle
);
518 // if a file was selected before, let's try to open
519 // the directory dialog on the same directory
520 if (!uriText
.getText().isEmpty()) {
522 // first we try if this is a simple file name
523 File testFile
= new File(uriText
.getText());
524 if (testFile
.exists()) {
525 dialog
.setFilterPath(testFile
.getPath());
527 // this could still be a file URIish
528 URIish testUri
= new URIish(uriText
.getText());
529 if (Protocol
.FILE
.defaultScheme
530 .equals(testUri
.getScheme())) {
531 testFile
= new File(testUri
.getPath());
532 if (testFile
.exists()) {
533 dialog
.setFilterPath(testFile
.getPath());
537 } catch (IllegalArgumentException
| URISyntaxException e
) {
538 // ignore here, we just' don't set the directory in the
542 // if nothing else, we start the search from the default folder for repositories
543 String filterPath
= dialog
.getFilterPath();
544 if (filterPath
== null || filterPath
.isEmpty()) {
545 dialog
.setFilterPath(
546 RepositoryUtil
.getDefaultRepositoryDir());
548 String result
= dialog
.open();
549 if (result
!= null) {
550 uriText
.setText("file:///" + result
); //$NON-NLS-1$
556 newLabel(g
, UIText
.RepositorySelectionPage_promptHost
+ ":"); //$NON-NLS-1$
557 hostText
= new Text(g
, SWT
.BORDER
);
558 GridDataFactory
.fillDefaults().span(2, 1).applyTo(hostText
);
559 hostText
.addModifyListener(new ModifyListener() {
561 public void modifyText(final ModifyEvent e
) {
562 setURI(uri
.setHost(nullString(hostText
.getText())));
566 newLabel(g
, UIText
.RepositorySelectionPage_promptPath
+ ":"); //$NON-NLS-1$
567 pathText
= new Text(g
, SWT
.BORDER
);
568 GridDataFactory
.fillDefaults().span(2, 1).applyTo(pathText
);
569 pathText
.addModifyListener(new ModifyListener() {
571 public void modifyText(final ModifyEvent e
) {
572 setURI(uri
.setPath(nullString(pathText
.getText())));
578 private Group
createAuthenticationGroup(final Composite parent
) {
579 final Group g
= createGroup(parent
,
580 UIText
.RepositorySelectionPage_groupAuthentication
);
582 newLabel(g
, UIText
.RepositorySelectionPage_promptUser
+ ":"); //$NON-NLS-1$
583 userText
= new Text(g
, SWT
.BORDER
);
584 userText
.setLayoutData(createFieldGridData());
585 userText
.addModifyListener(new ModifyListener() {
587 public void modifyText(final ModifyEvent e
) {
588 Protocol protocol
= getProtocol();
589 if (protocol
!= Protocol
.HTTP
&& protocol
!= Protocol
.HTTPS
)
590 setURI(uri
.setUser(nullString(userText
.getText())));
591 user
= userText
.getText();
595 newLabel(g
, UIText
.RepositorySelectionPage_promptPassword
+ ":"); //$NON-NLS-1$
596 passText
= new Text(g
, SWT
.BORDER
| SWT
.PASSWORD
);
597 passText
.setLayoutData(createFieldGridData());
598 passText
.addModifyListener(new ModifyListener() {
600 public void modifyText(final ModifyEvent e
) {
601 setURI(uri
.setPass(null));
602 password
= passText
.getText();
606 storeCheckbox
= new Button(g
, SWT
.CHECK
);
608 .setText(UIText
.RepositorySelectionPage_storeInSecureStore
);
609 storeCheckbox
.setSelection(storeInSecureStore
);
610 storeCheckbox
.addSelectionListener(new SelectionListener() {
612 public void widgetSelected(SelectionEvent e
) {
613 storeInSecureStore
= storeCheckbox
.getSelection();
617 public void widgetDefaultSelected(SelectionEvent e
) {
618 storeInSecureStore
= storeCheckbox
.getSelection();
625 private void createConnectionGroup(final Composite parent
) {
626 final Group g
= createGroup(parent
,
627 UIText
.RepositorySelectionPage_groupConnection
);
629 newLabel(g
, UIText
.RepositorySelectionPage_promptScheme
+ ":"); //$NON-NLS-1$
630 scheme
= new Combo(g
, SWT
.DROP_DOWN
| SWT
.READ_ONLY
);
631 for (Protocol p
: Protocol
.values())
632 scheme
.add(p
.getDefaultScheme());
633 scheme
.addSelectionListener(new SelectionAdapter() {
635 public void widgetSelected(final SelectionEvent e
) {
636 final int idx
= scheme
.getSelectionIndex();
638 setURI(uri
.setScheme(null));
639 scheme
.setToolTipText(EMPTY_STRING
);
641 setURI(uri
.setScheme(nullString(scheme
.getItem(idx
))));
642 scheme
.setToolTipText(Protocol
.values()[idx
].getTooltip());
648 newLabel(g
, UIText
.RepositorySelectionPage_promptPort
+ ":"); //$NON-NLS-1$
649 portText
= new Text(g
, SWT
.BORDER
);
650 portText
.addVerifyListener(new VerifyListener() {
651 final Pattern p
= Pattern
.compile("^(?:[1-9][0-9]*)?$"); //$NON-NLS-1$
654 public void verifyText(final VerifyEvent e
) {
655 final String v
= portText
.getText();
657 v
.substring(0, e
.start
) + e
.text
+ v
.substring(e
.end
))
661 portText
.addModifyListener(new ModifyListener() {
663 public void modifyText(final ModifyEvent e
) {
664 final String val
= nullString(portText
.getText());
666 setURI(uri
.setPort(-1));
669 setURI(uri
.setPort(Integer
.parseInt(val
)));
670 } catch (NumberFormatException err
) {
671 // Ignore it for now.
677 private Group
createGroup(final Composite parent
, final String text
) {
678 final Group g
= new Group(parent
, SWT
.NONE
);
679 final GridLayout layout
= new GridLayout();
680 layout
.numColumns
= 2;
683 final GridData gd
= new GridData();
684 gd
.grabExcessHorizontalSpace
= true;
685 gd
.horizontalAlignment
= SWT
.FILL
;
690 private void newLabel(final Group g
, final String text
) {
691 new Label(g
, SWT
.NULL
).setText(text
);
694 private GridData
createFieldGridData() {
695 return new GridData(SWT
.FILL
, SWT
.DEFAULT
, true, false);
698 private String
nullString(final String value
) {
701 final String v
= value
.trim();
702 return v
.length() == 0 ?
null : v
;
705 private void safeSet(final Text text
, final String value
) {
706 text
.setText(value
!= null ? value
: EMPTY_STRING
);
709 private boolean isURISelected() {
710 return uriButton
== null || uriButton
.getSelection();
713 private void setURI(final URIish u
) {
716 if (eventDepth
== 1) {
718 String oldUriText
= uriText
.getText();
719 String newUriText
= uri
.toString();
720 // avoid moving the cursor to the first position if there are no
721 // changes by this automatic update
722 if (!oldUriText
.equals(newUriText
)) {
723 uriText
.setText(newUriText
);
732 private List
<RemoteConfig
> getUsableConfigs(final List
<RemoteConfig
> remotes
) {
737 List
<RemoteConfig
> result
= new ArrayList
<>();
739 for (RemoteConfig config
: remotes
)
740 if ((sourceSelection
&& !config
.getURIs().isEmpty() || !sourceSelection
741 && (!config
.getPushURIs().isEmpty() || !config
.getURIs()
745 if (!result
.isEmpty())
752 * Check the user input and set messages in case of invalid input.
754 protected void checkPage() {
755 if (isURISelected()) {
757 if (uriText
.getText().length() == 0) {
758 selectionIncomplete(null);
760 } else if (uriText
.getText().endsWith(" ")) { //$NON-NLS-1$
761 selectionIncomplete(UIText
.RepositorySelectionPage_UriMustNotHaveTrailingSpacesMessage
);
766 final URIish finalURI
= new URIish(
767 GitUrlChecker
.sanitizeAsGitUrl(uriText
.getText()));
768 String proto
= finalURI
.getScheme();
769 if (proto
== null && scheme
.getSelectionIndex() >= 0)
770 proto
= scheme
.getItem(scheme
.getSelectionIndex());
772 if (uri
.getPath() == null) {
773 selectionIncomplete(NLS
.bind(
774 UIText
.RepositorySelectionPage_fieldRequired
,
775 unamp(UIText
.RepositorySelectionPage_promptPath
),
780 if (Protocol
.FILE
.handles(finalURI
)) {
781 String badField
= null;
782 if (uri
.getHost() != null)
783 badField
= UIText
.RepositorySelectionPage_promptHost
;
784 else if (uri
.getUser() != null)
785 badField
= UIText
.RepositorySelectionPage_promptUser
;
786 else if (uri
.getPass() != null)
787 badField
= UIText
.RepositorySelectionPage_promptPassword
;
788 if (badField
!= null) {
789 selectionIncomplete(NLS
791 UIText
.RepositorySelectionPage_fieldNotSupported
,
792 unamp(badField
), proto
));
796 final File d
= FS
.DETECTED
.resolve(
797 new File("."), uri
.getPath()); //$NON-NLS-1$
799 selectionIncomplete(NLS
.bind(
800 UIText
.RepositorySelectionPage_fileNotFound
,
801 d
.getAbsolutePath()));
805 selectionComplete(finalURI
, null);
809 if (uri
.getHost() == null) {
810 selectionIncomplete(NLS
.bind(
811 UIText
.RepositorySelectionPage_fieldRequired
,
812 unamp(UIText
.RepositorySelectionPage_promptHost
),
817 if (Protocol
.GIT
.handles(finalURI
)) {
818 String badField
= null;
819 if (uri
.getUser() != null)
820 badField
= UIText
.RepositorySelectionPage_promptUser
;
821 else if (uri
.getPass() != null)
822 badField
= UIText
.RepositorySelectionPage_promptPassword
;
823 if (badField
!= null) {
824 selectionIncomplete(NLS
826 UIText
.RepositorySelectionPage_fieldNotSupported
,
827 unamp(badField
), proto
));
832 if (Protocol
.HTTP
.handles(finalURI
)
833 || Protocol
.HTTPS
.handles(finalURI
)) {
834 UserPasswordCredentials credentials
= SecureStoreUtils
835 .getCredentials(finalURI
);
836 if (credentials
!= null) {
837 String u
= credentials
.getUser();
838 String p
= credentials
.getPassword();
839 String uriUser
= finalURI
.getUser();
840 if (uriUser
== null) {
841 if (setSafeUser(u
) && setSafePassword(p
))
842 setStoreInSecureStore(true);
843 } else if (uriUser
.length() != 0 && uriUser
.equals(u
)) {
844 if (setSafePassword(p
))
845 setStoreInSecureStore(true);
850 selectionComplete(finalURI
, null);
852 } catch (URISyntaxException e
) {
853 selectionIncomplete(e
.getReason());
855 } catch (Exception e
) {
856 Activator
.logError(NLS
.bind(
857 UIText
.RepositorySelectionPage_errorValidating
,
858 getClass().getName()), e
);
859 selectionIncomplete(UIText
.RepositorySelectionPage_internalError
);
863 assert remoteButton
.getSelection();
864 selectionComplete(null, remoteConfig
);
869 private boolean setSafePassword(String p
) {
870 if ((password
== null || password
.length() == 0) && p
!= null
871 && p
.length() != 0) {
879 private boolean setSafeUser(String u
) {
880 if ((user
== null || user
.length() == 0) && u
!= null
881 && u
.length() != 0) {
889 private void setStoreInSecureStore(boolean store
) {
890 storeInSecureStore
= store
;
891 storeCheckbox
.setSelection(store
);
894 private String
unamp(String s
) {
895 return s
.replace("&", EMPTY_STRING
); //$NON-NLS-1$
898 private void selectionIncomplete(final String errorMessage
) {
899 setExposedSelection(null, null);
900 setErrorMessage(errorMessage
);
901 setPageComplete(false);
904 private void selectionComplete(final URIish u
, final RemoteConfig rc
) {
905 setExposedSelection(u
, rc
);
906 setErrorMessage(null);
907 setPageComplete(true);
910 private void setExposedSelection(final URIish u
, final RemoteConfig rc
) {
911 final RepositorySelection newSelection
= new RepositorySelection(u
, rc
);
912 if (newSelection
.equals(selection
))
915 selection
= newSelection
;
918 private void updateRemoteAndURIPanels() {
919 UIUtils
.setEnabledRecursively(uriPanel
, isURISelected());
920 if (uriPanel
.getEnabled())
922 if (configuredRemotes
!= null)
923 UIUtils
.setEnabledRecursively(remotePanel
, !isURISelected());
926 private void updateGroups() {
927 Protocol p
= getProtocol();
929 hostText
.setEnabled(p
.hasHost());
931 hostText
.setText(EMPTY_STRING
);
932 portText
.setEnabled(p
.hasPort());
934 portText
.setText(EMPTY_STRING
);
936 UIUtils
.setEnabledRecursively(authGroup
, p
.canAuthenticate());
937 if (!p
.canAuthenticate()) {
938 userText
.setText(EMPTY_STRING
);
939 passText
.setText(EMPTY_STRING
);
940 storeCheckbox
.setSelection(false);
945 private Protocol
getProtocol() {
946 int idx
= scheme
.getSelectionIndex();
948 return Protocol
.values()[idx
];
953 public void setVisible(boolean visible
) {
954 super.setVisible(visible
);
960 * Updates the proposal list for the URI field
962 public void saveUriInPrefs() {
963 uriProposalHandler
.updateProposals();
967 * @return credentials
969 public UserPasswordCredentials
getCredentials() {
970 if ((user
== null || user
.length() == 0)
971 && (password
== null || password
.length() == 0))
973 return new UserPasswordCredentials(user
, password
);
977 * @return true if credentials should be stored
979 public boolean getStoreInSecureStore() {
980 return this.storeInSecureStore
;
984 * Set the ID for context sensitive help
989 public void setHelpContext(String id
) {
994 public void performHelp() {
995 PlatformUI
.getWorkbench().getHelpSystem().displayHelp(helpContext
);
998 private void updateFields(final String text
) {
1001 if (eventDepth
!= 1)
1004 String strippedText
= GitUrlChecker
.sanitizeAsGitUrl(text
);
1005 final URIish u
= new URIish(strippedText
);
1006 if (!text
.equals(strippedText
)) {
1007 uriText
.setText(strippedText
);
1009 safeSet(hostText
, u
.getHost());
1010 safeSet(pathText
, u
.getPath());
1011 safeSet(userText
, u
.getUser());
1012 safeSet(passText
, u
.getPass());
1014 if (u
.getPort() > 0)
1015 portText
.setText(Integer
.toString(u
.getPort()));
1017 portText
.setText(EMPTY_STRING
);
1019 if (u
.getScheme() != null) {
1020 scheme
.select(scheme
.indexOf(u
.getScheme()));
1021 scheme
.notifyListeners(SWT
.Selection
, new Event());
1026 } catch (URISyntaxException err
) {
1027 // leave uriText as it is, but clean up underlying uri and
1028 // decomposed fields
1030 hostText
.setText(EMPTY_STRING
);
1031 pathText
.setText(EMPTY_STRING
);
1032 userText
.setText(EMPTY_STRING
);
1033 passText
.setText(EMPTY_STRING
);
1034 portText
.setText(EMPTY_STRING
);
1042 private IPreferenceStore
getPreferenceStore() {
1043 return Activator
.getDefault().getPreferenceStore();
1047 public GitRepositoryInfo
getGitRepositoryInfo() {
1048 GitRepositoryInfo info
= new GitRepositoryInfo(uri
.toString());
1049 info
.setCredentials(user
, password
);
1050 info
.setShouldSaveCredentialsInSecureStore(storeInSecureStore
);
1051 uriProposalHandler
.updateProposals();