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
.List
;
19 import java
.util
.StringTokenizer
;
20 import java
.util
.regex
.Pattern
;
21 import java
.util
.regex
.PatternSyntaxException
;
23 import org
.eclipse
.core
.runtime
.preferences
.IEclipsePreferences
;
24 import org
.eclipse
.core
.runtime
.preferences
.InstanceScope
;
25 import org
.eclipse
.egit
.ui
.Activator
;
26 import org
.eclipse
.egit
.ui
.UIText
;
27 import org
.eclipse
.egit
.ui
.UIUtils
;
28 import org
.eclipse
.jface
.dialogs
.Dialog
;
29 import org
.eclipse
.jface
.fieldassist
.ContentProposalAdapter
;
30 import org
.eclipse
.jface
.fieldassist
.IContentProposal
;
31 import org
.eclipse
.jface
.fieldassist
.IContentProposalProvider
;
32 import org
.eclipse
.jface
.fieldassist
.TextContentAdapter
;
33 import org
.eclipse
.jface
.layout
.GridDataFactory
;
34 import org
.eclipse
.jgit
.lib
.Constants
;
35 import org
.eclipse
.jgit
.transport
.RemoteConfig
;
36 import org
.eclipse
.jgit
.transport
.Transport
;
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
.dnd
.Clipboard
;
42 import org
.eclipse
.swt
.dnd
.TextTransfer
;
43 import org
.eclipse
.swt
.events
.ModifyEvent
;
44 import org
.eclipse
.swt
.events
.ModifyListener
;
45 import org
.eclipse
.swt
.events
.SelectionAdapter
;
46 import org
.eclipse
.swt
.events
.SelectionEvent
;
47 import org
.eclipse
.swt
.events
.VerifyEvent
;
48 import org
.eclipse
.swt
.events
.VerifyListener
;
49 import org
.eclipse
.swt
.layout
.GridData
;
50 import org
.eclipse
.swt
.layout
.GridLayout
;
51 import org
.eclipse
.swt
.widgets
.Button
;
52 import org
.eclipse
.swt
.widgets
.Combo
;
53 import org
.eclipse
.swt
.widgets
.Composite
;
54 import org
.eclipse
.swt
.widgets
.Control
;
55 import org
.eclipse
.swt
.widgets
.DirectoryDialog
;
56 import org
.eclipse
.swt
.widgets
.Display
;
57 import org
.eclipse
.swt
.widgets
.Group
;
58 import org
.eclipse
.swt
.widgets
.Label
;
59 import org
.eclipse
.swt
.widgets
.Text
;
60 import org
.osgi
.service
.prefs
.BackingStoreException
;
63 * Wizard page that allows the user entering the location of a remote repository
64 * by specifying URL manually or selecting a preconfigured remote repository.
66 public class RepositorySelectionPage
extends BaseWizardPage
{
68 private final static String USED_URIS_PREF
= "RepositorySelectionPage.UsedUris"; //$NON-NLS-1$
70 private final static String USED_URIS_LENGTH_PREF
= "RepositorySelectionPage.UsedUrisLength"; //$NON-NLS-1$
72 private static final int REMOTE_CONFIG_TEXT_MAX_LENGTH
= 80;
74 private static final int S_GIT
= 0;
76 private static final int S_SSH
= 1;
78 private static final int S_SFTP
= 2;
80 private static final int S_HTTP
= 3;
82 private static final int S_HTTPS
= 4;
84 private static final int S_FTP
= 5;
86 private static final int S_FILE
= 6;
88 private static final String
[] DEFAULT_SCHEMES
;
91 DEFAULT_SCHEMES
= new String
[7];
92 DEFAULT_SCHEMES
[S_GIT
] = "git"; //$NON-NLS-1$
93 DEFAULT_SCHEMES
[S_SSH
] = "git+ssh"; //$NON-NLS-1$
94 DEFAULT_SCHEMES
[S_SFTP
] = "sftp"; //$NON-NLS-1$
95 DEFAULT_SCHEMES
[S_HTTP
] = "http"; //$NON-NLS-1$
96 DEFAULT_SCHEMES
[S_HTTPS
] = "https"; //$NON-NLS-1$
97 DEFAULT_SCHEMES
[S_FTP
] = "ftp"; //$NON-NLS-1$
98 DEFAULT_SCHEMES
[S_FILE
] = "file"; //$NON-NLS-1$
101 private final List
<RemoteConfig
> configuredRemotes
;
103 private final boolean sourceSelection
;
105 private final String presetUri
;
107 private Group authGroup
;
109 private Text uriText
;
111 private Text hostText
;
113 private Text pathText
;
115 private Text userText
;
117 private Text passText
;
119 private Combo scheme
;
121 private Text portText
;
123 private int eventDepth
;
127 private RemoteConfig remoteConfig
;
129 private RepositorySelection selection
;
131 private Composite remotePanel
;
133 private Button remoteButton
;
135 private Combo remoteCombo
;
137 private Composite uriPanel
;
139 private Button uriButton
;
142 * Create repository selection page, allowing user specifying URI or
143 * (optionally) choosing from preconfigured remotes list.
145 * Wizard page is created without image, just with text description.
147 * @param sourceSelection
148 * true if dialog is used for source selection; false otherwise
149 * (destination selection). This indicates appropriate text
151 * @param configuredRemotes
152 * list of configured remotes that user may select as an
153 * alternative to manual URI specification. Remotes appear in
154 * given order in GUI, with
155 * {@value Constants#DEFAULT_REMOTE_NAME} as the default choice.
156 * List may be null or empty - no remotes configurations appear
157 * in this case. Note that the provided list may be changed by
160 * the pre-set URI, may be null
162 public RepositorySelectionPage(final boolean sourceSelection
,
163 final List
<RemoteConfig
> configuredRemotes
, String presetUri
) {
165 super(RepositorySelectionPage
.class.getName());
167 this.uri
= new URIish();
168 this.sourceSelection
= sourceSelection
;
170 String preset
= null;
171 if (presetUri
== null) {
172 Clipboard clippy
= new Clipboard(Display
.getCurrent());
173 String text
= (String
) clippy
.getContents(TextTransfer
.getInstance());
177 if(Transport
.canHandleProtocol(new URIish(text
), FS
.DETECTED
))
180 } catch (URISyntaxException e
) {
185 this.presetUri
= preset
;
187 this.configuredRemotes
= getUsableConfigs(configuredRemotes
);
188 this.remoteConfig
= selectDefaultRemoteConfig();
190 selection
= RepositorySelection
.INVALID_SELECTION
;
192 if (sourceSelection
) {
193 setTitle(UIText
.RepositorySelectionPage_sourceSelectionTitle
);
194 setDescription(UIText
.RepositorySelectionPage_sourceSelectionDescription
);
196 setTitle(UIText
.RepositorySelectionPage_destinationSelectionTitle
);
197 setDescription(UIText
.RepositorySelectionPage_destinationSelectionDescription
);
202 * Create repository selection page, allowing user specifying URI, with no
203 * preconfigured remotes selection.
205 * @param sourceSelection
206 * true if dialog is used for source selection; false otherwise
207 * (destination selection). This indicates appropriate text
210 * the pre-set URI, may be null
212 public RepositorySelectionPage(final boolean sourceSelection
,
214 this(sourceSelection
, null, presetUri
);
218 * @return repository selection representing current page state.
220 public RepositorySelection
getSelection() {
225 * Compare current repository selection set by user to provided one.
228 * repository selection to compare.
229 * @return true if provided selection is equal to current page selection,
232 public boolean selectionEquals(final RepositorySelection s
) {
233 return selection
.equals(s
);
236 public void createControl(final Composite parent
) {
237 final Composite panel
= new Composite(parent
, SWT
.NULL
);
238 panel
.setLayout(new GridLayout());
240 if (configuredRemotes
!= null)
241 createRemotePanel(panel
);
243 createUriPanel(panel
);
245 if(presetUri
!= null)
246 updateFields(presetUri
);
248 updateRemoteAndURIPanels();
249 Dialog
.applyDialogFont(panel
);
255 private void createRemotePanel(final Composite parent
) {
256 remoteButton
= new Button(parent
, SWT
.RADIO
);
258 .setText(UIText
.RepositorySelectionPage_configuredRemoteChoice
259 + ":"); //$NON-NLS-1$
260 remoteButton
.setSelection(true);
262 remotePanel
= new Composite(parent
, SWT
.NULL
);
263 remotePanel
.setLayout(new GridLayout());
264 final GridData gd
= new GridData();
265 gd
.grabExcessHorizontalSpace
= true;
266 gd
.horizontalAlignment
= SWT
.FILL
;
267 remotePanel
.setLayoutData(gd
);
269 remoteCombo
= new Combo(remotePanel
, SWT
.READ_ONLY
| SWT
.DROP_DOWN
);
270 final String items
[] = new String
[configuredRemotes
.size()];
272 for (final RemoteConfig rc
: configuredRemotes
)
273 items
[i
++] = getTextForRemoteConfig(rc
);
274 final int defaultIndex
= configuredRemotes
.indexOf(remoteConfig
);
275 remoteCombo
.setItems(items
);
276 remoteCombo
.select(defaultIndex
);
277 remoteCombo
.addSelectionListener(new SelectionAdapter() {
279 public void widgetSelected(SelectionEvent e
) {
280 final int idx
= remoteCombo
.getSelectionIndex();
281 remoteConfig
= configuredRemotes
.get(idx
);
287 private void createUriPanel(final Composite parent
) {
288 if (configuredRemotes
!= null) {
289 uriButton
= new Button(parent
, SWT
.RADIO
);
290 uriButton
.setText(UIText
.RepositorySelectionPage_uriChoice
+ ":"); //$NON-NLS-1$
291 uriButton
.addSelectionListener(new SelectionAdapter() {
292 public void widgetSelected(SelectionEvent e
) {
293 // occurs either on selection or unselection event
294 updateRemoteAndURIPanels();
300 uriPanel
= new Composite(parent
, SWT
.NULL
);
301 uriPanel
.setLayout(new GridLayout());
302 final GridData gd
= new GridData();
303 gd
.grabExcessHorizontalSpace
= true;
304 gd
.horizontalAlignment
= SWT
.FILL
;
305 uriPanel
.setLayoutData(gd
);
307 createLocationGroup(uriPanel
);
308 createConnectionGroup(uriPanel
);
309 authGroup
= createAuthenticationGroup(uriPanel
);
312 private void createLocationGroup(final Composite parent
) {
313 final Group g
= createGroup(parent
,
314 UIText
.RepositorySelectionPage_groupLocation
);
316 g
.setLayout(new GridLayout(3, false));
318 newLabel(g
, UIText
.RepositorySelectionPage_promptURI
+ ":"); //$NON-NLS-1$
319 uriText
= new Text(g
, SWT
.BORDER
);
321 if (presetUri
!= null)
322 uriText
.setText(presetUri
);
324 uriText
.setLayoutData(createFieldGridData());
325 uriText
.addModifyListener(new ModifyListener() {
326 public void modifyText(final ModifyEvent e
) {
327 updateFields(uriText
.getText());
331 addContentProposalToUriText(uriText
);
333 Button browseButton
= new Button(g
, SWT
.NULL
);
334 browseButton
.setText(UIText
.RepositorySelectionPage_BrowseLocalFile
);
335 browseButton
.addSelectionListener(new SelectionAdapter() {
338 public void widgetSelected(SelectionEvent e
) {
339 DirectoryDialog dialog
= new DirectoryDialog(getShell());
340 // if a file-uri was selected before, let's try to open
341 // the directory dialog on the same directory
342 if (!uriText
.getText().equals("")) { //$NON-NLS-1$
344 URI testUri
= URI
.create(uriText
.getText().replace(
346 if (testUri
.getScheme().equals("file")) { //$NON-NLS-1$
347 String path
= testUri
.getPath();
348 if (path
.length() > 1 && path
.startsWith("/")) //$NON-NLS-1$
349 path
= path
.substring(1);
351 dialog
.setFilterPath(path
);
353 } catch (IllegalArgumentException e1
) {
354 // ignore here, we just' don't set the directory in the
359 String result
= dialog
.open();
361 uriText
.setText("file:///" + result
); //$NON-NLS-1$
366 newLabel(g
, UIText
.RepositorySelectionPage_promptHost
+ ":"); //$NON-NLS-1$
367 hostText
= new Text(g
, SWT
.BORDER
);
368 GridDataFactory
.fillDefaults().span(2, 1).applyTo(hostText
);
369 hostText
.addModifyListener(new ModifyListener() {
370 public void modifyText(final ModifyEvent e
) {
371 setURI(uri
.setHost(nullString(hostText
.getText())));
375 newLabel(g
, UIText
.RepositorySelectionPage_promptPath
+ ":"); //$NON-NLS-1$
376 pathText
= new Text(g
, SWT
.BORDER
);
377 GridDataFactory
.fillDefaults().span(2, 1).applyTo(pathText
);
378 pathText
.addModifyListener(new ModifyListener() {
379 public void modifyText(final ModifyEvent e
) {
380 setURI(uri
.setPath(nullString(pathText
.getText())));
386 private Group
createAuthenticationGroup(final Composite parent
) {
387 final Group g
= createGroup(parent
,
388 UIText
.RepositorySelectionPage_groupAuthentication
);
390 newLabel(g
, UIText
.RepositorySelectionPage_promptUser
+ ":"); //$NON-NLS-1$
391 userText
= new Text(g
, SWT
.BORDER
);
392 userText
.setLayoutData(createFieldGridData());
393 userText
.addModifyListener(new ModifyListener() {
394 public void modifyText(final ModifyEvent e
) {
395 setURI(uri
.setUser(nullString(userText
.getText())));
399 newLabel(g
, UIText
.RepositorySelectionPage_promptPassword
+ ":"); //$NON-NLS-1$
400 passText
= new Text(g
, SWT
.BORDER
| SWT
.PASSWORD
);
401 passText
.setLayoutData(createFieldGridData());
405 private void createConnectionGroup(final Composite parent
) {
406 final Group g
= createGroup(parent
,
407 UIText
.RepositorySelectionPage_groupConnection
);
409 newLabel(g
, UIText
.RepositorySelectionPage_promptScheme
+ ":"); //$NON-NLS-1$
410 scheme
= new Combo(g
, SWT
.DROP_DOWN
| SWT
.READ_ONLY
);
411 scheme
.setItems(DEFAULT_SCHEMES
);
412 scheme
.addSelectionListener(new SelectionAdapter() {
413 public void widgetSelected(final SelectionEvent e
) {
414 final int idx
= scheme
.getSelectionIndex();
416 setURI(uri
.setScheme(null));
418 setURI(uri
.setScheme(nullString(scheme
.getItem(idx
))));
423 newLabel(g
, UIText
.RepositorySelectionPage_promptPort
+ ":"); //$NON-NLS-1$
424 portText
= new Text(g
, SWT
.BORDER
);
425 portText
.addVerifyListener(new VerifyListener() {
426 final Pattern p
= Pattern
.compile("^(?:[1-9][0-9]*)?$"); //$NON-NLS-1$
428 public void verifyText(final VerifyEvent e
) {
429 final String v
= portText
.getText();
431 v
.substring(0, e
.start
) + e
.text
+ v
.substring(e
.end
))
435 portText
.addModifyListener(new ModifyListener() {
436 public void modifyText(final ModifyEvent e
) {
437 final String val
= nullString(portText
.getText());
439 setURI(uri
.setPort(-1));
442 setURI(uri
.setPort(Integer
.parseInt(val
)));
443 } catch (NumberFormatException err
) {
444 // Ignore it for now.
451 private Group
createGroup(final Composite parent
, final String text
) {
452 final Group g
= new Group(parent
, SWT
.NONE
);
453 final GridLayout layout
= new GridLayout();
454 layout
.numColumns
= 2;
457 final GridData gd
= new GridData();
458 gd
.grabExcessHorizontalSpace
= true;
459 gd
.horizontalAlignment
= SWT
.FILL
;
464 private void newLabel(final Group g
, final String text
) {
465 new Label(g
, SWT
.NULL
).setText(text
);
468 private GridData
createFieldGridData() {
469 return new GridData(SWT
.FILL
, SWT
.DEFAULT
, true, false);
472 private boolean isGIT(final URIish uri
) {
473 return "git".equals(uri
.getScheme()); //$NON-NLS-1$
476 private boolean isFile(final URIish uri
) {
477 if ("file".equals(uri
.getScheme()) || uri
.getScheme() == null) //$NON-NLS-1$
479 if (uri
.getHost() != null || uri
.getPort() > 0 || uri
.getUser() != null
480 || uri
.getPass() != null || uri
.getPath() == null)
482 if (uri
.getScheme() == null)
483 return FS
.DETECTED
.resolve(new File("."), uri
.getPath()).isDirectory(); //$NON-NLS-1$
487 private boolean isSSH(final URIish uri
) {
490 final String scheme
= uri
.getScheme();
491 if ("ssh".equals(scheme
)) //$NON-NLS-1$
493 if ("ssh+git".equals(scheme
)) //$NON-NLS-1$
495 if ("git+ssh".equals(scheme
)) //$NON-NLS-1$
497 if (scheme
== null && uri
.getHost() != null && uri
.getPath() != null)
502 private String
nullString(final String value
) {
505 final String v
= value
.trim();
506 return v
.length() == 0 ?
null : v
;
509 private void safeSet(final Text text
, final String value
) {
510 text
.setText(value
!= null ? value
: ""); //$NON-NLS-1$
513 private boolean isURISelected() {
514 return configuredRemotes
== null || presetUri
!= null
515 || uriButton
.getSelection();
518 private void setURI(final URIish u
) {
521 if (eventDepth
== 1) {
523 uriText
.setText(uri
.toString());
531 private List
<RemoteConfig
> getUsableConfigs(final List
<RemoteConfig
> remotes
) {
536 List
<RemoteConfig
> result
= new ArrayList
<RemoteConfig
>();
538 for (RemoteConfig config
: remotes
)
539 if ((sourceSelection
&& !config
.getURIs().isEmpty() || !sourceSelection
540 && (!config
.getPushURIs().isEmpty() || !config
.getURIs()
544 if (!result
.isEmpty())
550 private RemoteConfig
selectDefaultRemoteConfig() {
551 if (configuredRemotes
== null)
553 for (final RemoteConfig rc
: configuredRemotes
)
554 if (Constants
.DEFAULT_REMOTE_NAME
.equals(rc
.getName()))
556 return configuredRemotes
.get(0);
559 private String
getTextForRemoteConfig(final RemoteConfig rc
) {
560 final StringBuilder sb
= new StringBuilder(rc
.getName());
561 sb
.append(": "); //$NON-NLS-1$
562 boolean first
= true;
564 if (sourceSelection
) {
567 uris
= rc
.getPushURIs();
568 // if no push URIs are defined, use fetch URIs instead
569 if (uris
.isEmpty()) {
574 for (final URIish u
: uris
) {
575 final String uString
= u
.toString();
579 sb
.append(", "); //$NON-NLS-1$
580 if (sb
.length() + uString
.length() > REMOTE_CONFIG_TEXT_MAX_LENGTH
) {
581 sb
.append("..."); //$NON-NLS-1$
587 return sb
.toString();
590 private void checkPage() {
591 if (isURISelected()) {
593 if (uriText
.getText().length() == 0) {
594 selectionIncomplete(null);
599 final URIish finalURI
= new URIish(uriText
.getText());
600 String proto
= finalURI
.getScheme();
601 if (proto
== null && scheme
.getSelectionIndex() >= 0)
602 proto
= scheme
.getItem(scheme
.getSelectionIndex());
604 if (uri
.getPath() == null) {
605 selectionIncomplete(NLS
.bind(
606 UIText
.RepositorySelectionPage_fieldRequired
,
607 unamp(UIText
.RepositorySelectionPage_promptPath
),
612 if (isFile(finalURI
)) {
613 String badField
= null;
614 if (uri
.getHost() != null)
615 badField
= UIText
.RepositorySelectionPage_promptHost
;
616 else if (uri
.getUser() != null)
617 badField
= UIText
.RepositorySelectionPage_promptUser
;
618 else if (uri
.getPass() != null)
619 badField
= UIText
.RepositorySelectionPage_promptPassword
;
620 if (badField
!= null) {
621 selectionIncomplete(NLS
623 UIText
.RepositorySelectionPage_fieldNotSupported
,
624 unamp(badField
), proto
));
628 final File d
= FS
.DETECTED
.resolve(new File("."), uri
.getPath()); //$NON-NLS-1$
630 selectionIncomplete(NLS
.bind(
631 UIText
.RepositorySelectionPage_fileNotFound
, d
632 .getAbsolutePath()));
636 selectionComplete(finalURI
, null);
640 if (uri
.getHost() == null) {
641 selectionIncomplete(NLS
.bind(
642 UIText
.RepositorySelectionPage_fieldRequired
,
643 unamp(UIText
.RepositorySelectionPage_promptHost
),
648 if (isGIT(finalURI
)) {
649 String badField
= null;
650 if (uri
.getUser() != null)
651 badField
= UIText
.RepositorySelectionPage_promptUser
;
652 else if (uri
.getPass() != null)
653 badField
= UIText
.RepositorySelectionPage_promptPassword
;
654 if (badField
!= null) {
655 selectionIncomplete(NLS
657 UIText
.RepositorySelectionPage_fieldNotSupported
,
658 unamp(badField
), proto
));
663 selectionComplete(finalURI
, null);
665 } catch (URISyntaxException e
) {
666 selectionIncomplete(e
.getReason());
668 } catch (Exception e
) {
669 Activator
.logError(NLS
.bind(
670 UIText
.RepositorySelectionPage_errorValidating
,
671 getClass().getName()),
673 selectionIncomplete(UIText
.RepositorySelectionPage_internalError
);
677 assert remoteButton
.getSelection();
678 selectionComplete(null, remoteConfig
);
683 private String
unamp(String s
) {
684 return s
.replace("&", ""); //$NON-NLS-1$ //$NON-NLS-2$
687 private void selectionIncomplete(final String errorMessage
) {
688 setExposedSelection(null, null);
689 setErrorMessage(errorMessage
);
690 setPageComplete(false);
693 private void selectionComplete(final URIish u
, final RemoteConfig rc
) {
694 setExposedSelection(u
, rc
);
695 setErrorMessage(null);
696 setPageComplete(true);
697 notifySelectionChanged();
700 private void setExposedSelection(final URIish u
, final RemoteConfig rc
) {
701 final RepositorySelection newSelection
= new RepositorySelection(u
, rc
);
702 if (newSelection
.equals(selection
))
705 selection
= newSelection
;
706 notifySelectionChanged();
709 private void updateRemoteAndURIPanels() {
710 setEnabledRecursively(uriPanel
, isURISelected());
711 if (uriPanel
.getEnabled())
713 if (configuredRemotes
!= null)
714 setEnabledRecursively(remotePanel
, !isURISelected());
717 private void updateAuthGroup() {
718 switch (scheme
.getSelectionIndex()) {
720 hostText
.setEnabled(true);
721 portText
.setEnabled(true);
722 setEnabledRecursively(authGroup
, false);
729 hostText
.setEnabled(true);
730 portText
.setEnabled(true);
731 setEnabledRecursively(authGroup
, true);
734 hostText
.setEnabled(false);
735 portText
.setEnabled(false);
736 setEnabledRecursively(authGroup
, false);
742 public void setVisible(boolean visible
) {
743 super.setVisible(visible
);
749 * Adds a URI string to the list of previously added ones
751 * TODO move this to some proper preferences handling class instead of
756 public static void saveUriInPrefs(String stringToAdd
) {
758 List
<String
> uriStrings
= getUrisFromPrefs();
760 if (uriStrings
.indexOf(stringToAdd
) == 0)
762 uriStrings
.add(0, stringToAdd
);
764 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
767 StringBuilder sb
= new StringBuilder();
768 StringBuilder lb
= new StringBuilder();
770 // there is no "good" separator for URIish, so we
771 // keep track of the URI lengths separately
772 for (String uriString
: uriStrings
) {
773 sb
.append(uriString
);
774 lb
.append(uriString
.length());
775 lb
.append(" "); //$NON-NLS-1$
777 prefs
.put(USED_URIS_PREF
, sb
.toString());
778 prefs
.put(USED_URIS_LENGTH_PREF
, lb
.toString());
782 } catch (BackingStoreException e
) {
783 // we simply ignore this here
788 * Gets the previously added URIs from the preferences
790 * TODO move this to some proper preferences handling class instead of
793 * @return a (possibly empty) list of URIs, never <code>null</code>
795 public static List
<String
> getUrisFromPrefs() {
797 // use a TreeSet to get the same sorting always
798 List
<String
> uriStrings
= new ArrayList
<String
>();
800 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
802 // since there is no "good" separator for URIish, so we
803 // keep track of the URI lengths separately
804 String uriLengths
= prefs
.get(USED_URIS_LENGTH_PREF
, ""); //$NON-NLS-1$
805 String uris
= prefs
.get(USED_URIS_PREF
, ""); //$NON-NLS-1$
807 StringTokenizer tok
= new StringTokenizer(uriLengths
, " "); //$NON-NLS-1$
809 while (tok
.hasMoreTokens()) {
811 int length
= Integer
.parseInt(tok
.nextToken());
812 if (uris
.length() >= (offset
+ length
)) {
813 uriStrings
.add(uris
.substring(offset
, offset
+ length
));
816 } catch (NumberFormatException nfe
) {
825 private void setEnabledRecursively(final Control control
,
826 final boolean enable
) {
827 control
.setEnabled(enable
);
828 if (control
instanceof Composite
)
829 for (final Control child
: ((Composite
) control
).getChildren())
830 setEnabledRecursively(child
, enable
);
833 private void addContentProposalToUriText(Text uriTextField
) {
835 UIUtils
.addBulbDecorator(uriTextField
, UIText
.RepositorySelectionPage_ShowPreviousURIs_HoverText
);
837 IContentProposalProvider cp
= new IContentProposalProvider() {
839 public IContentProposal
[] getProposals(String contents
, int position
) {
841 List
<IContentProposal
> resultList
= new ArrayList
<IContentProposal
>();
843 String patternString
= contents
;
844 while (patternString
.length() > 0
845 && patternString
.charAt(0) == ' ')
846 patternString
= patternString
.substring(1);
847 // make the simplest possible pattern check: allow "*"
848 // for multiple characters
849 patternString
= patternString
.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
850 // make sure we add a (logical) * at the end
851 if (!patternString
.endsWith(".*")) { //$NON-NLS-1$
852 patternString
= patternString
+ ".*"; //$NON-NLS-1$
854 // let's compile a case-insensitive pattern (assumes ASCII only)
857 pattern
= Pattern
.compile(patternString
,
858 Pattern
.CASE_INSENSITIVE
);
859 } catch (PatternSyntaxException e
) {
863 List
<String
> uriStrings
= getUrisFromPrefs();
864 for (final String uriString
: uriStrings
) {
867 && !pattern
.matcher(uriString
).matches())
870 IContentProposal propsal
= new IContentProposal() {
872 public String
getLabel() {
876 public String
getDescription() {
880 public int getCursorPosition() {
884 public String
getContent() {
888 resultList
.add(propsal
);
891 return resultList
.toArray(new IContentProposal
[resultList
896 // set the acceptance style to always replace the complete content
897 new ContentProposalAdapter(uriTextField
, new TextContentAdapter(), cp
,
899 .setProposalAcceptanceStyle(ContentProposalAdapter
.PROPOSAL_REPLACE
);
903 private void updateFields(final String text
) {
909 final URIish u
= new URIish(text
);
910 safeSet(hostText
, u
.getHost());
911 safeSet(pathText
, u
.getPath());
912 safeSet(userText
, u
.getUser());
913 safeSet(passText
, u
.getPass());
916 portText
.setText(Integer
.toString(u
.getPort()));
918 portText
.setText(""); //$NON-NLS-1$
921 scheme
.select(S_FILE
);
923 scheme
.select(S_SSH
);
925 for (int i
= 0; i
< DEFAULT_SCHEMES
.length
; i
++) {
926 if (DEFAULT_SCHEMES
[i
].equals(u
.getScheme())) {
935 } catch (URISyntaxException err
) {
936 // leave uriText as it is, but clean up underlying uri and
939 hostText
.setText(""); //$NON-NLS-1$
940 pathText
.setText(""); //$NON-NLS-1$
941 userText
.setText(""); //$NON-NLS-1$
942 passText
.setText(""); //$NON-NLS-1$
943 portText
.setText(""); //$NON-NLS-1$