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>
7 * All rights reserved. This program and the accompanying materials
8 * are made available under the terms of the Eclipse Public License v1.0
9 * which accompanies this distribution, and is available at
10 * http://www.eclipse.org/legal/epl-v10.html
11 *******************************************************************************/
12 package org
.eclipse
.egit
.ui
.internal
.components
;
16 import java
.net
.URISyntaxException
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Iterator
;
19 import java
.util
.List
;
20 import java
.util
.StringTokenizer
;
21 import java
.util
.regex
.Pattern
;
22 import java
.util
.regex
.PatternSyntaxException
;
24 import org
.eclipse
.core
.runtime
.preferences
.IEclipsePreferences
;
25 import org
.eclipse
.core
.runtime
.preferences
.InstanceScope
;
26 import org
.eclipse
.egit
.ui
.Activator
;
27 import org
.eclipse
.egit
.ui
.UIText
;
28 import org
.eclipse
.jface
.fieldassist
.ContentProposalAdapter
;
29 import org
.eclipse
.jface
.fieldassist
.ControlDecoration
;
30 import org
.eclipse
.jface
.fieldassist
.FieldDecorationRegistry
;
31 import org
.eclipse
.jface
.fieldassist
.IContentProposal
;
32 import org
.eclipse
.jface
.fieldassist
.IContentProposalProvider
;
33 import org
.eclipse
.jface
.fieldassist
.TextContentAdapter
;
34 import org
.eclipse
.jface
.layout
.GridDataFactory
;
35 import org
.eclipse
.jgit
.lib
.Constants
;
36 import org
.eclipse
.jgit
.transport
.RemoteConfig
;
37 import org
.eclipse
.jgit
.transport
.URIish
;
38 import org
.eclipse
.jgit
.util
.FS
;
39 import org
.eclipse
.osgi
.util
.NLS
;
40 import org
.eclipse
.swt
.SWT
;
41 import org
.eclipse
.swt
.events
.ModifyEvent
;
42 import org
.eclipse
.swt
.events
.ModifyListener
;
43 import org
.eclipse
.swt
.events
.SelectionAdapter
;
44 import org
.eclipse
.swt
.events
.SelectionEvent
;
45 import org
.eclipse
.swt
.events
.VerifyEvent
;
46 import org
.eclipse
.swt
.events
.VerifyListener
;
47 import org
.eclipse
.swt
.layout
.GridData
;
48 import org
.eclipse
.swt
.layout
.GridLayout
;
49 import org
.eclipse
.swt
.widgets
.Button
;
50 import org
.eclipse
.swt
.widgets
.Combo
;
51 import org
.eclipse
.swt
.widgets
.Composite
;
52 import org
.eclipse
.swt
.widgets
.Control
;
53 import org
.eclipse
.swt
.widgets
.DirectoryDialog
;
54 import org
.eclipse
.swt
.widgets
.Group
;
55 import org
.eclipse
.swt
.widgets
.Label
;
56 import org
.eclipse
.swt
.widgets
.Text
;
57 import org
.osgi
.service
.prefs
.BackingStoreException
;
61 * Wizard page that allows the user entering the location of a remote repository
62 * by specifying URL manually or selecting a preconfigured remote repository.
64 public class RepositorySelectionPage
extends BaseWizardPage
{
65 private final static String USED_URIS_PREF
= "RepositorySelectionPage.UsedUris"; //$NON-NLS-1$
66 private final static String USED_URIS_LENGTH_PREF
= "RepositorySelectionPage.UsedUrisLength"; //$NON-NLS-1$
68 private static final int REMOTE_CONFIG_TEXT_MAX_LENGTH
= 80;
70 private static final int S_GIT
= 0;
72 private static final int S_SSH
= 1;
74 private static final int S_SFTP
= 2;
76 private static final int S_HTTP
= 3;
78 private static final int S_HTTPS
= 4;
80 private static final int S_FTP
= 5;
82 private static final int S_FILE
= 6;
84 private static final String
[] DEFAULT_SCHEMES
;
86 DEFAULT_SCHEMES
= new String
[7];
87 DEFAULT_SCHEMES
[S_GIT
] = "git"; //$NON-NLS-1$
88 DEFAULT_SCHEMES
[S_SSH
] = "git+ssh"; //$NON-NLS-1$
89 DEFAULT_SCHEMES
[S_SFTP
] = "sftp"; //$NON-NLS-1$
90 DEFAULT_SCHEMES
[S_HTTP
] = "http"; //$NON-NLS-1$
91 DEFAULT_SCHEMES
[S_HTTPS
] = "https"; //$NON-NLS-1$
92 DEFAULT_SCHEMES
[S_FTP
] = "ftp"; //$NON-NLS-1$
93 DEFAULT_SCHEMES
[S_FILE
] = "file"; //$NON-NLS-1$
96 private static void setEnabledRecursively(final Control control
,
97 final boolean enable
) {
98 control
.setEnabled(enable
);
99 if (control
instanceof Composite
)
100 for (final Control child
: ((Composite
) control
).getChildren())
101 setEnabledRecursively(child
, enable
);
104 private final List
<RemoteConfig
> configuredRemotes
;
106 private final boolean sourceSelection
;
108 private Group authGroup
;
110 private Text uriText
;
112 private Text hostText
;
114 private Text pathText
;
116 private Text userText
;
118 private Text passText
;
120 private Combo scheme
;
122 private Text portText
;
124 private int eventDepth
;
128 private RemoteConfig remoteConfig
;
130 private RepositorySelection selection
;
132 private Composite remotePanel
;
134 private Button remoteButton
;
136 private Combo remoteCombo
;
138 private Composite uriPanel
;
140 private Button uriButton
;
142 private String presetUri
;
145 * Create repository selection page, allowing user specifying URI or
146 * (optionally) choosing from preconfigured remotes list.
148 * Wizard page is created without image, just with text description.
150 * @param sourceSelection
151 * true if dialog is used for source selection; false otherwise
152 * (destination selection). This indicates appropriate text
154 * @param configuredRemotes
155 * list of configured remotes that user may select as an
156 * alternative to manual URI specification. Remotes appear in
157 * given order in GUI, with {@value Constants#DEFAULT_REMOTE_NAME} as the
158 * default choice. List may be null or empty - no remotes
159 * configurations appear in this case. Note that the provided
160 * list may be changed by this constructor.
162 public RepositorySelectionPage(final boolean sourceSelection
,
163 final List
<RemoteConfig
> configuredRemotes
) {
164 this(sourceSelection
, configuredRemotes
, null);
168 * Special case: the URI is set externally
170 * @param sourceSelection
171 * true if dialog is used for source selection; false otherwise
172 * (destination selection). This indicates appropriate text
174 * @param configuredRemotes
175 * list of configured remotes that user may select as an
176 * alternative to manual URI specification. Remotes appear in
177 * given order in GUI, with
178 * {@value Constants#DEFAULT_REMOTE_NAME} as the default choice.
179 * List may be null or empty - no remotes configurations appear
180 * in this case. Note that the provided list may be changed by
185 public RepositorySelectionPage(final boolean sourceSelection
,
186 final List
<RemoteConfig
> configuredRemotes
, String presetUri
) {
187 super(RepositorySelectionPage
.class.getName());
188 this.uri
= new URIish();
189 this.sourceSelection
= sourceSelection
;
190 this.presetUri
= presetUri
;
192 if (configuredRemotes
!= null)
193 removeUnusableRemoteConfigs(configuredRemotes
);
194 if (configuredRemotes
== null || configuredRemotes
.isEmpty())
195 this.configuredRemotes
= null;
197 this.configuredRemotes
= configuredRemotes
;
198 this.remoteConfig
= selectDefaultRemoteConfig();
200 selection
= RepositorySelection
.INVALID_SELECTION
;
202 if (sourceSelection
) {
203 setTitle(UIText
.RepositorySelectionPage_sourceSelectionTitle
);
204 setDescription(UIText
.RepositorySelectionPage_sourceSelectionDescription
);
206 setTitle(UIText
.RepositorySelectionPage_destinationSelectionTitle
);
207 setDescription(UIText
.RepositorySelectionPage_destinationSelectionDescription
);
212 * Create repository selection page, allowing user specifying URI, with no
213 * preconfigured remotes selection.
215 * @param sourceSelection
216 * true if dialog is used for source selection; false otherwise
217 * (destination selection). This indicates appropriate text
220 public RepositorySelectionPage(final boolean sourceSelection
) {
221 this(sourceSelection
, null, null);
226 * @return repository selection representing current page state.
228 public RepositorySelection
getSelection() {
233 * Compare current repository selection set by user to provided one.
236 * repository selection to compare.
237 * @return true if provided selection is equal to current page selection,
240 public boolean selectionEquals(final RepositorySelection s
) {
241 return selection
.equals(s
);
244 public void createControl(final Composite parent
) {
245 final Composite panel
= new Composite(parent
, SWT
.NULL
);
246 panel
.setLayout(new GridLayout());
248 if (configuredRemotes
!= null)
249 createRemotePanel(panel
);
250 createUriPanel(panel
);
252 updateRemoteAndURIPanels();
254 if (presetUri
!= null)
255 uriText
.setText(presetUri
);
260 private void createRemotePanel(final Composite parent
) {
261 remoteButton
= new Button(parent
, SWT
.RADIO
);
263 .setText(UIText
.RepositorySelectionPage_configuredRemoteChoice
264 + ":"); //$NON-NLS-1$
265 remoteButton
.setSelection(true);
267 remotePanel
= new Composite(parent
, SWT
.NULL
);
268 remotePanel
.setLayout(new GridLayout());
269 final GridData gd
= new GridData();
270 gd
.grabExcessHorizontalSpace
= true;
271 gd
.horizontalAlignment
= SWT
.FILL
;
272 remotePanel
.setLayoutData(gd
);
274 remoteCombo
= new Combo(remotePanel
, SWT
.READ_ONLY
| SWT
.DROP_DOWN
);
275 final String items
[] = new String
[configuredRemotes
.size()];
277 for (final RemoteConfig rc
: configuredRemotes
)
278 items
[i
++] = getTextForRemoteConfig(rc
);
279 final int defaultIndex
= configuredRemotes
.indexOf(remoteConfig
);
280 remoteCombo
.setItems(items
);
281 remoteCombo
.select(defaultIndex
);
282 remoteCombo
.addSelectionListener(new SelectionAdapter() {
284 public void widgetSelected(SelectionEvent e
) {
285 final int idx
= remoteCombo
.getSelectionIndex();
286 remoteConfig
= configuredRemotes
.get(idx
);
292 private void createUriPanel(final Composite parent
) {
293 if (configuredRemotes
!= null) {
294 uriButton
= new Button(parent
, SWT
.RADIO
);
295 uriButton
.setText(UIText
.RepositorySelectionPage_uriChoice
+ ":"); //$NON-NLS-1$
296 uriButton
.addSelectionListener(new SelectionAdapter() {
297 public void widgetSelected(SelectionEvent e
) {
298 // occurs either on selection or unselection event
299 updateRemoteAndURIPanels();
305 uriPanel
= new Composite(parent
, SWT
.NULL
);
306 uriPanel
.setLayout(new GridLayout());
307 final GridData gd
= new GridData();
308 gd
.grabExcessHorizontalSpace
= true;
309 gd
.horizontalAlignment
= SWT
.FILL
;
310 uriPanel
.setLayoutData(gd
);
312 createLocationGroup(uriPanel
);
313 createConnectionGroup(uriPanel
);
314 authGroup
= createAuthenticationGroup(uriPanel
);
317 private void createLocationGroup(final Composite parent
) {
318 final Group g
= createGroup(parent
,
319 UIText
.RepositorySelectionPage_groupLocation
);
321 g
.setLayout(new GridLayout(3, false));
323 newLabel(g
, UIText
.RepositorySelectionPage_promptURI
+ ":"); //$NON-NLS-1$
324 uriText
= new Text(g
, SWT
.BORDER
);
325 uriText
.setLayoutData(createFieldGridData());
326 uriText
.addModifyListener(new ModifyListener() {
327 public void modifyText(final ModifyEvent e
) {
333 final URIish u
= new URIish(uriText
.getText());
334 safeSet(hostText
, u
.getHost());
335 safeSet(pathText
, u
.getPath());
336 safeSet(userText
, u
.getUser());
337 safeSet(passText
, u
.getPass());
340 portText
.setText(Integer
.toString(u
.getPort()));
342 portText
.setText(""); //$NON-NLS-1$
345 scheme
.select(S_FILE
);
347 scheme
.select(S_SSH
);
349 for (int i
= 0; i
< DEFAULT_SCHEMES
.length
; i
++) {
350 if (DEFAULT_SCHEMES
[i
].equals(u
.getScheme())) {
359 } catch (URISyntaxException err
) {
360 // leave uriText as it is, but clean up underlying uri and
363 hostText
.setText(""); //$NON-NLS-1$
364 pathText
.setText(""); //$NON-NLS-1$
365 userText
.setText(""); //$NON-NLS-1$
366 passText
.setText(""); //$NON-NLS-1$
367 portText
.setText(""); //$NON-NLS-1$
376 addContentProposalToUriText(uriText
);
378 Button browseButton
= new Button(g
, SWT
.NULL
);
379 browseButton
.setText(UIText
.RepositorySelectionPage_BrowseLocalFile
);
380 browseButton
.addSelectionListener(new SelectionAdapter() {
383 public void widgetSelected(SelectionEvent e
) {
384 DirectoryDialog dialog
= new DirectoryDialog(getShell());
385 // if a file-uri was selected before, let's try to open
386 // the directory dialog on the same directory
387 if (!uriText
.getText().equals("")) { //$NON-NLS-1$
389 URI testUri
= URI
.create(uriText
.getText().replace(
391 if (testUri
.getScheme().equals("file")) { //$NON-NLS-1$
392 String path
= testUri
.getPath();
393 if (path
.length() > 1 && path
.startsWith("/")) //$NON-NLS-1$
394 path
= path
.substring(1);
396 dialog
.setFilterPath(path
);
398 } catch (IllegalArgumentException e1
) {
399 // ignore here, we just' don't set the directory in the
404 String result
= dialog
.open();
406 uriText
.setText("file:///" + result
); //$NON-NLS-1$
411 newLabel(g
, UIText
.RepositorySelectionPage_promptHost
+ ":"); //$NON-NLS-1$
412 hostText
= new Text(g
, SWT
.BORDER
);
413 GridDataFactory
.fillDefaults().span(2, 1).applyTo(hostText
);
414 hostText
.addModifyListener(new ModifyListener() {
415 public void modifyText(final ModifyEvent e
) {
416 setURI(uri
.setHost(nullString(hostText
.getText())));
420 newLabel(g
, UIText
.RepositorySelectionPage_promptPath
+ ":"); //$NON-NLS-1$
421 pathText
= new Text(g
, SWT
.BORDER
);
422 GridDataFactory
.fillDefaults().span(2, 1).applyTo(pathText
);
423 pathText
.addModifyListener(new ModifyListener() {
424 public void modifyText(final ModifyEvent e
) {
425 setURI(uri
.setPath(nullString(pathText
.getText())));
430 private Group
createAuthenticationGroup(final Composite parent
) {
431 final Group g
= createGroup(parent
,
432 UIText
.RepositorySelectionPage_groupAuthentication
);
434 newLabel(g
, UIText
.RepositorySelectionPage_promptUser
+ ":"); //$NON-NLS-1$
435 userText
= new Text(g
, SWT
.BORDER
);
436 userText
.setLayoutData(createFieldGridData());
437 userText
.addModifyListener(new ModifyListener() {
438 public void modifyText(final ModifyEvent e
) {
439 setURI(uri
.setUser(nullString(userText
.getText())));
443 newLabel(g
, UIText
.RepositorySelectionPage_promptPassword
+ ":"); //$NON-NLS-1$
444 passText
= new Text(g
, SWT
.BORDER
| SWT
.PASSWORD
);
445 passText
.setLayoutData(createFieldGridData());
449 private void createConnectionGroup(final Composite parent
) {
450 final Group g
= createGroup(parent
,
451 UIText
.RepositorySelectionPage_groupConnection
);
453 newLabel(g
, UIText
.RepositorySelectionPage_promptScheme
+ ":"); //$NON-NLS-1$
454 scheme
= new Combo(g
, SWT
.DROP_DOWN
| SWT
.READ_ONLY
);
455 scheme
.setItems(DEFAULT_SCHEMES
);
456 scheme
.addSelectionListener(new SelectionAdapter() {
457 public void widgetSelected(final SelectionEvent e
) {
458 final int idx
= scheme
.getSelectionIndex();
460 setURI(uri
.setScheme(null));
462 setURI(uri
.setScheme(nullString(scheme
.getItem(idx
))));
467 newLabel(g
, UIText
.RepositorySelectionPage_promptPort
+ ":"); //$NON-NLS-1$
468 portText
= new Text(g
, SWT
.BORDER
);
469 portText
.addVerifyListener(new VerifyListener() {
470 final Pattern p
= Pattern
.compile("^(?:[1-9][0-9]*)?$"); //$NON-NLS-1$
472 public void verifyText(final VerifyEvent e
) {
473 final String v
= portText
.getText();
475 v
.substring(0, e
.start
) + e
.text
+ v
.substring(e
.end
))
479 portText
.addModifyListener(new ModifyListener() {
480 public void modifyText(final ModifyEvent e
) {
481 final String val
= nullString(portText
.getText());
483 setURI(uri
.setPort(-1));
486 setURI(uri
.setPort(Integer
.parseInt(val
)));
487 } catch (NumberFormatException err
) {
488 // Ignore it for now.
495 private static Group
createGroup(final Composite parent
, final String text
) {
496 final Group g
= new Group(parent
, SWT
.NONE
);
497 final GridLayout layout
= new GridLayout();
498 layout
.numColumns
= 2;
501 final GridData gd
= new GridData();
502 gd
.grabExcessHorizontalSpace
= true;
503 gd
.horizontalAlignment
= SWT
.FILL
;
508 private static void newLabel(final Group g
, final String text
) {
509 new Label(g
, SWT
.NULL
).setText(text
);
512 private static GridData
createFieldGridData() {
513 return new GridData(SWT
.FILL
, SWT
.DEFAULT
, true, false);
516 private static boolean isGIT(final URIish uri
) {
517 return "git".equals(uri
.getScheme()); //$NON-NLS-1$
520 private static boolean isFile(final URIish uri
) {
521 if ("file".equals(uri
.getScheme()) || uri
.getScheme() == null) //$NON-NLS-1$
523 if (uri
.getHost() != null || uri
.getPort() > 0 || uri
.getUser() != null
524 || uri
.getPass() != null || uri
.getPath() == null)
526 if (uri
.getScheme() == null)
527 return FS
.resolve(new File("."), uri
.getPath()).isDirectory(); //$NON-NLS-1$
531 private static boolean isSSH(final URIish uri
) {
534 final String scheme
= uri
.getScheme();
535 if ("ssh".equals(scheme
)) //$NON-NLS-1$
537 if ("ssh+git".equals(scheme
)) //$NON-NLS-1$
539 if ("git+ssh".equals(scheme
)) //$NON-NLS-1$
541 if (scheme
== null && uri
.getHost() != null && uri
.getPath() != null)
546 private static String
nullString(final String value
) {
549 final String v
= value
.trim();
550 return v
.length() == 0 ?
null : v
;
553 private static void safeSet(final Text text
, final String value
) {
554 text
.setText(value
!= null ? value
: ""); //$NON-NLS-1$
557 private boolean isURISelected() {
558 return configuredRemotes
== null || presetUri
!= null || uriButton
.getSelection();
561 private void setURI(final URIish u
) {
564 if (eventDepth
== 1) {
566 uriText
.setText(uri
.toString());
574 private static void removeUnusableRemoteConfigs(
575 final List
<RemoteConfig
> remotes
) {
576 final Iterator
<RemoteConfig
> iter
= remotes
.iterator();
577 while (iter
.hasNext()) {
578 final RemoteConfig rc
= iter
.next();
579 if (rc
.getURIs().isEmpty())
584 private RemoteConfig
selectDefaultRemoteConfig() {
585 for (final RemoteConfig rc
: configuredRemotes
)
586 if (Constants
.DEFAULT_REMOTE_NAME
.equals(getTextForRemoteConfig(rc
)))
588 return configuredRemotes
.get(0);
591 private String
getTextForRemoteConfig(final RemoteConfig rc
) {
592 final StringBuilder sb
= new StringBuilder(rc
.getName());
593 sb
.append(": "); //$NON-NLS-1$
594 boolean first
= true;
596 if (sourceSelection
) {
599 // TODO shouldn't this be getPushURIs?
600 uris
= rc
.getPushURIs();
603 for (final URIish u
: uris
) {
604 final String uString
= u
.toString();
608 sb
.append(", "); //$NON-NLS-1$
609 if (sb
.length() + uString
.length() > REMOTE_CONFIG_TEXT_MAX_LENGTH
) {
610 sb
.append("..."); //$NON-NLS-1$
616 return sb
.toString();
619 private void checkPage() {
620 if (isURISelected()) {
622 if (uriText
.getText().length() == 0) {
623 selectionIncomplete(null);
628 final URIish finalURI
= new URIish(uriText
.getText());
629 String proto
= finalURI
.getScheme();
630 if (proto
== null && scheme
.getSelectionIndex() >= 0)
631 proto
= scheme
.getItem(scheme
.getSelectionIndex());
633 if (uri
.getPath() == null) {
634 selectionIncomplete(NLS
.bind(
635 UIText
.RepositorySelectionPage_fieldRequired
,
636 unamp(UIText
.RepositorySelectionPage_promptPath
), proto
));
640 if (isFile(finalURI
)) {
641 String badField
= null;
642 if (uri
.getHost() != null)
643 badField
= UIText
.RepositorySelectionPage_promptHost
;
644 else if (uri
.getUser() != null)
645 badField
= UIText
.RepositorySelectionPage_promptUser
;
646 else if (uri
.getPass() != null)
647 badField
= UIText
.RepositorySelectionPage_promptPassword
;
648 if (badField
!= null) {
649 selectionIncomplete(NLS
651 UIText
.RepositorySelectionPage_fieldNotSupported
,
652 unamp(badField
), proto
));
656 final File d
= FS
.resolve(new File("."), uri
.getPath()); //$NON-NLS-1$
658 selectionIncomplete(NLS
.bind(
659 UIText
.RepositorySelectionPage_fileNotFound
, d
660 .getAbsolutePath()));
664 selectionComplete(finalURI
, null);
668 if (uri
.getHost() == null) {
669 selectionIncomplete(NLS
.bind(
670 UIText
.RepositorySelectionPage_fieldRequired
,
671 unamp(UIText
.RepositorySelectionPage_promptHost
), proto
));
675 if (isGIT(finalURI
)) {
676 String badField
= null;
677 if (uri
.getUser() != null)
678 badField
= UIText
.RepositorySelectionPage_promptUser
;
679 else if (uri
.getPass() != null)
680 badField
= UIText
.RepositorySelectionPage_promptPassword
;
681 if (badField
!= null) {
682 selectionIncomplete(NLS
684 UIText
.RepositorySelectionPage_fieldNotSupported
,
685 unamp(badField
), proto
));
690 selectionComplete(finalURI
, null);
692 } catch (URISyntaxException e
) {
693 selectionIncomplete(e
.getReason());
695 } catch (Exception e
) {
696 Activator
.logError(NLS
.bind(
697 UIText
.RepositorySelectionPage_errorValidating
,
698 getClass().getName()),
700 selectionIncomplete(UIText
.RepositorySelectionPage_internalError
);
704 assert remoteButton
.getSelection();
705 selectionComplete(null, remoteConfig
);
710 private String
unamp(String s
) {
711 return s
.replace("&",""); //$NON-NLS-1$ //$NON-NLS-2$
714 private void selectionIncomplete(final String errorMessage
) {
715 setExposedSelection(null, null);
716 setErrorMessage(errorMessage
);
717 setPageComplete(false);
720 private void selectionComplete(final URIish u
, final RemoteConfig rc
) {
721 setExposedSelection(u
, rc
);
722 setErrorMessage(null);
723 setPageComplete(true);
726 private void setExposedSelection(final URIish u
, final RemoteConfig rc
) {
727 final RepositorySelection newSelection
= new RepositorySelection(u
, rc
);
728 if (newSelection
.equals(selection
))
731 selection
= newSelection
;
732 notifySelectionChanged();
735 private void updateRemoteAndURIPanels() {
736 setEnabledRecursively(uriPanel
, isURISelected());
737 if (uriPanel
.getEnabled())
739 if (configuredRemotes
!= null)
740 setEnabledRecursively(remotePanel
, !isURISelected());
743 private void updateAuthGroup() {
744 switch (scheme
.getSelectionIndex()) {
746 hostText
.setEnabled(true);
747 portText
.setEnabled(true);
748 setEnabledRecursively(authGroup
, false);
755 hostText
.setEnabled(true);
756 portText
.setEnabled(true);
757 setEnabledRecursively(authGroup
, true);
760 hostText
.setEnabled(false);
761 portText
.setEnabled(false);
762 setEnabledRecursively(authGroup
, false);
768 public void setVisible(boolean visible
) {
769 super.setVisible(visible
);
775 * Adds a URI string to the list of previously added ones
779 public void saveUriInPrefs(String stringToAdd
) {
781 List
<String
> uriStrings
= getUrisFromPrefs();
783 if (uriStrings
.indexOf(stringToAdd
) == 0)
785 uriStrings
.add(0, stringToAdd
);
787 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
790 StringBuilder sb
= new StringBuilder();
791 StringBuilder lb
= new StringBuilder();
793 // there is no "good" separator for URIish, so we
794 // keep track of the URI lengths separately
795 for (String uriString
: uriStrings
) {
796 sb
.append(uriString
);
797 lb
.append(uriString
.length());
798 lb
.append(" "); //$NON-NLS-1$
800 prefs
.put(USED_URIS_PREF
, sb
.toString());
801 prefs
.put(USED_URIS_LENGTH_PREF
, lb
.toString());
805 } catch (BackingStoreException e
) {
806 // we simply ignore this here
811 * Gets the previously added URIs from the preferences
813 * @return a (possibly empty) list of URIs, never <code>null</code>
815 public List
<String
> getUrisFromPrefs() {
817 // use a TreeSet to get the same sorting always
818 List
<String
> uriStrings
= new ArrayList
<String
>();
820 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
822 // since there is no "good" separator for URIish, so we
823 // keep track of the URI lengths separately
824 String uriLengths
= prefs
.get(USED_URIS_LENGTH_PREF
, ""); //$NON-NLS-1$
825 String uris
= prefs
.get(USED_URIS_PREF
, ""); //$NON-NLS-1$
827 StringTokenizer tok
= new StringTokenizer(uriLengths
, " "); //$NON-NLS-1$
829 while (tok
.hasMoreTokens()) {
831 int length
= Integer
.parseInt(tok
.nextToken());
832 if (uris
.length() >= (offset
+ length
)) {
833 uriStrings
.add(uris
.substring(offset
, offset
+ length
));
836 } catch (NumberFormatException nfe
) {
845 private void addContentProposalToUriText(Text uriTextField
) {
847 ControlDecoration dec
= new ControlDecoration(uriTextField
, SWT
.TOP
850 dec
.setImage(FieldDecorationRegistry
.getDefault().getFieldDecoration(
851 FieldDecorationRegistry
.DEC_CONTENT_PROPOSAL
).getImage());
853 dec
.setShowOnlyOnFocus(true);
854 dec
.setShowHover(true);
856 dec
.setDescriptionText(UIText
.RepositorySelectionPage_ShowPreviousURIs_HoverText
);
858 IContentProposalProvider cp
= new IContentProposalProvider() {
860 public IContentProposal
[] getProposals(String contents
, int position
) {
862 List
<IContentProposal
> resultList
= new ArrayList
<IContentProposal
>();
864 String patternString
= contents
;
865 while (patternString
.length() > 0 && patternString
.charAt(0)==' ')
866 patternString
= patternString
.substring(1);
867 // make the simplest possible pattern check: allow "*"
868 // for multiple characters
869 patternString
= patternString
.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
870 // make sure we add a (logical) * at the end
871 if (!patternString
.endsWith(".*")) { //$NON-NLS-1$
872 patternString
= patternString
+ ".*"; //$NON-NLS-1$
874 // let's compile a case-insensitive pattern (assumes ASCII only)
877 pattern
= Pattern
.compile(patternString
,
878 Pattern
.CASE_INSENSITIVE
);
879 } catch (PatternSyntaxException e
) {
883 List
<String
> uriStrings
= getUrisFromPrefs();
884 for (final String uriString
: uriStrings
) {
886 if (pattern
!=null && !pattern
.matcher(uriString
).matches())
889 IContentProposal propsal
= new IContentProposal() {
891 public String
getLabel() {
895 public String
getDescription() {
899 public int getCursorPosition() {
903 public String
getContent() {
907 resultList
.add(propsal
);
910 return resultList
.toArray(new IContentProposal
[resultList
915 // set the acceptance style to always replace the complete content
916 new ContentProposalAdapter(uriTextField
, new TextContentAdapter(), cp
,
918 .setProposalAcceptanceStyle(ContentProposalAdapter
.PROPOSAL_REPLACE
);