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
.fieldassist
.ContentProposalAdapter
;
29 import org
.eclipse
.jface
.fieldassist
.IContentProposal
;
30 import org
.eclipse
.jface
.fieldassist
.IContentProposalProvider
;
31 import org
.eclipse
.jface
.fieldassist
.TextContentAdapter
;
32 import org
.eclipse
.jface
.layout
.GridDataFactory
;
33 import org
.eclipse
.jgit
.lib
.Constants
;
34 import org
.eclipse
.jgit
.transport
.RemoteConfig
;
35 import org
.eclipse
.jgit
.transport
.Transport
;
36 import org
.eclipse
.jgit
.transport
.URIish
;
37 import org
.eclipse
.jgit
.util
.FS
;
38 import org
.eclipse
.osgi
.util
.NLS
;
39 import org
.eclipse
.swt
.SWT
;
40 import org
.eclipse
.swt
.dnd
.Clipboard
;
41 import org
.eclipse
.swt
.dnd
.TextTransfer
;
42 import org
.eclipse
.swt
.events
.ModifyEvent
;
43 import org
.eclipse
.swt
.events
.ModifyListener
;
44 import org
.eclipse
.swt
.events
.SelectionAdapter
;
45 import org
.eclipse
.swt
.events
.SelectionEvent
;
46 import org
.eclipse
.swt
.events
.VerifyEvent
;
47 import org
.eclipse
.swt
.events
.VerifyListener
;
48 import org
.eclipse
.swt
.layout
.GridData
;
49 import org
.eclipse
.swt
.layout
.GridLayout
;
50 import org
.eclipse
.swt
.widgets
.Button
;
51 import org
.eclipse
.swt
.widgets
.Combo
;
52 import org
.eclipse
.swt
.widgets
.Composite
;
53 import org
.eclipse
.swt
.widgets
.Control
;
54 import org
.eclipse
.swt
.widgets
.DirectoryDialog
;
55 import org
.eclipse
.swt
.widgets
.Display
;
56 import org
.eclipse
.swt
.widgets
.Group
;
57 import org
.eclipse
.swt
.widgets
.Label
;
58 import org
.eclipse
.swt
.widgets
.Text
;
59 import org
.osgi
.service
.prefs
.BackingStoreException
;
62 * Wizard page that allows the user entering the location of a remote repository
63 * by specifying URL manually or selecting a preconfigured remote repository.
65 public class RepositorySelectionPage
extends BaseWizardPage
{
67 private final static String USED_URIS_PREF
= "RepositorySelectionPage.UsedUris"; //$NON-NLS-1$
69 private final static String USED_URIS_LENGTH_PREF
= "RepositorySelectionPage.UsedUrisLength"; //$NON-NLS-1$
71 private static final int REMOTE_CONFIG_TEXT_MAX_LENGTH
= 80;
73 private static final int S_GIT
= 0;
75 private static final int S_SSH
= 1;
77 private static final int S_SFTP
= 2;
79 private static final int S_HTTP
= 3;
81 private static final int S_HTTPS
= 4;
83 private static final int S_FTP
= 5;
85 private static final int S_FILE
= 6;
87 private static final String
[] DEFAULT_SCHEMES
;
90 DEFAULT_SCHEMES
= new String
[7];
91 DEFAULT_SCHEMES
[S_GIT
] = "git"; //$NON-NLS-1$
92 DEFAULT_SCHEMES
[S_SSH
] = "git+ssh"; //$NON-NLS-1$
93 DEFAULT_SCHEMES
[S_SFTP
] = "sftp"; //$NON-NLS-1$
94 DEFAULT_SCHEMES
[S_HTTP
] = "http"; //$NON-NLS-1$
95 DEFAULT_SCHEMES
[S_HTTPS
] = "https"; //$NON-NLS-1$
96 DEFAULT_SCHEMES
[S_FTP
] = "ftp"; //$NON-NLS-1$
97 DEFAULT_SCHEMES
[S_FILE
] = "file"; //$NON-NLS-1$
100 private final List
<RemoteConfig
> configuredRemotes
;
102 private final boolean sourceSelection
;
104 private final String presetUri
;
106 private Group authGroup
;
108 private Text uriText
;
110 private Text hostText
;
112 private Text pathText
;
114 private Text userText
;
116 private Text passText
;
118 private Combo scheme
;
120 private Text portText
;
122 private int eventDepth
;
126 private RemoteConfig remoteConfig
;
128 private RepositorySelection selection
;
130 private Composite remotePanel
;
132 private Button remoteButton
;
134 private Combo remoteCombo
;
136 private Composite uriPanel
;
138 private Button uriButton
;
141 * Create repository selection page, allowing user specifying URI or
142 * (optionally) choosing from preconfigured remotes list.
144 * Wizard page is created without image, just with text description.
146 * @param sourceSelection
147 * true if dialog is used for source selection; false otherwise
148 * (destination selection). This indicates appropriate text
150 * @param configuredRemotes
151 * list of configured remotes that user may select as an
152 * alternative to manual URI specification. Remotes appear in
153 * given order in GUI, with
154 * {@value Constants#DEFAULT_REMOTE_NAME} as the default choice.
155 * List may be null or empty - no remotes configurations appear
156 * in this case. Note that the provided list may be changed by
159 * the pre-set URI, may be null
161 public RepositorySelectionPage(final boolean sourceSelection
,
162 final List
<RemoteConfig
> configuredRemotes
, String presetUri
) {
164 super(RepositorySelectionPage
.class.getName());
166 this.uri
= new URIish();
167 this.sourceSelection
= sourceSelection
;
169 String preset
= null;
170 if (presetUri
== null) {
171 Clipboard clippy
= new Clipboard(Display
.getCurrent());
172 String text
= (String
) clippy
.getContents(TextTransfer
.getInstance());
176 if(Transport
.canHandleProtocol(new URIish(text
)))
179 } catch (URISyntaxException e
) {
184 this.presetUri
= preset
;
186 this.configuredRemotes
= getUsableConfigs(configuredRemotes
);
187 this.remoteConfig
= selectDefaultRemoteConfig();
189 selection
= RepositorySelection
.INVALID_SELECTION
;
191 if (sourceSelection
) {
192 setTitle(UIText
.RepositorySelectionPage_sourceSelectionTitle
);
193 setDescription(UIText
.RepositorySelectionPage_sourceSelectionDescription
);
195 setTitle(UIText
.RepositorySelectionPage_destinationSelectionTitle
);
196 setDescription(UIText
.RepositorySelectionPage_destinationSelectionDescription
);
201 * Create repository selection page, allowing user specifying URI, with no
202 * preconfigured remotes selection.
204 * @param sourceSelection
205 * true if dialog is used for source selection; false otherwise
206 * (destination selection). This indicates appropriate text
209 * the pre-set URI, may be null
211 public RepositorySelectionPage(final boolean sourceSelection
,
213 this(sourceSelection
, null, presetUri
);
217 * @return repository selection representing current page state.
219 public RepositorySelection
getSelection() {
224 * Compare current repository selection set by user to provided one.
227 * repository selection to compare.
228 * @return true if provided selection is equal to current page selection,
231 public boolean selectionEquals(final RepositorySelection s
) {
232 return selection
.equals(s
);
235 public void createControl(final Composite parent
) {
236 final Composite panel
= new Composite(parent
, SWT
.NULL
);
237 panel
.setLayout(new GridLayout());
239 if (configuredRemotes
!= null)
240 createRemotePanel(panel
);
242 createUriPanel(panel
);
244 if(presetUri
!= null)
245 updateFields(presetUri
);
247 updateRemoteAndURIPanels();
253 private void createRemotePanel(final Composite parent
) {
254 remoteButton
= new Button(parent
, SWT
.RADIO
);
256 .setText(UIText
.RepositorySelectionPage_configuredRemoteChoice
257 + ":"); //$NON-NLS-1$
258 remoteButton
.setSelection(true);
260 remotePanel
= new Composite(parent
, SWT
.NULL
);
261 remotePanel
.setLayout(new GridLayout());
262 final GridData gd
= new GridData();
263 gd
.grabExcessHorizontalSpace
= true;
264 gd
.horizontalAlignment
= SWT
.FILL
;
265 remotePanel
.setLayoutData(gd
);
267 remoteCombo
= new Combo(remotePanel
, SWT
.READ_ONLY
| SWT
.DROP_DOWN
);
268 final String items
[] = new String
[configuredRemotes
.size()];
270 for (final RemoteConfig rc
: configuredRemotes
)
271 items
[i
++] = getTextForRemoteConfig(rc
);
272 final int defaultIndex
= configuredRemotes
.indexOf(remoteConfig
);
273 remoteCombo
.setItems(items
);
274 remoteCombo
.select(defaultIndex
);
275 remoteCombo
.addSelectionListener(new SelectionAdapter() {
277 public void widgetSelected(SelectionEvent e
) {
278 final int idx
= remoteCombo
.getSelectionIndex();
279 remoteConfig
= configuredRemotes
.get(idx
);
285 private void createUriPanel(final Composite parent
) {
286 if (configuredRemotes
!= null) {
287 uriButton
= new Button(parent
, SWT
.RADIO
);
288 uriButton
.setText(UIText
.RepositorySelectionPage_uriChoice
+ ":"); //$NON-NLS-1$
289 uriButton
.addSelectionListener(new SelectionAdapter() {
290 public void widgetSelected(SelectionEvent e
) {
291 // occurs either on selection or unselection event
292 updateRemoteAndURIPanels();
298 uriPanel
= new Composite(parent
, SWT
.NULL
);
299 uriPanel
.setLayout(new GridLayout());
300 final GridData gd
= new GridData();
301 gd
.grabExcessHorizontalSpace
= true;
302 gd
.horizontalAlignment
= SWT
.FILL
;
303 uriPanel
.setLayoutData(gd
);
305 createLocationGroup(uriPanel
);
306 createConnectionGroup(uriPanel
);
307 authGroup
= createAuthenticationGroup(uriPanel
);
310 private void createLocationGroup(final Composite parent
) {
311 final Group g
= createGroup(parent
,
312 UIText
.RepositorySelectionPage_groupLocation
);
314 g
.setLayout(new GridLayout(3, false));
316 newLabel(g
, UIText
.RepositorySelectionPage_promptURI
+ ":"); //$NON-NLS-1$
317 uriText
= new Text(g
, SWT
.BORDER
);
319 if (presetUri
!= null)
320 uriText
.setText(presetUri
);
322 uriText
.setLayoutData(createFieldGridData());
323 uriText
.addModifyListener(new ModifyListener() {
324 public void modifyText(final ModifyEvent e
) {
325 updateFields(uriText
.getText());
329 addContentProposalToUriText(uriText
);
331 Button browseButton
= new Button(g
, SWT
.NULL
);
332 browseButton
.setText(UIText
.RepositorySelectionPage_BrowseLocalFile
);
333 browseButton
.addSelectionListener(new SelectionAdapter() {
336 public void widgetSelected(SelectionEvent e
) {
337 DirectoryDialog dialog
= new DirectoryDialog(getShell());
338 // if a file-uri was selected before, let's try to open
339 // the directory dialog on the same directory
340 if (!uriText
.getText().equals("")) { //$NON-NLS-1$
342 URI testUri
= URI
.create(uriText
.getText().replace(
344 if (testUri
.getScheme().equals("file")) { //$NON-NLS-1$
345 String path
= testUri
.getPath();
346 if (path
.length() > 1 && path
.startsWith("/")) //$NON-NLS-1$
347 path
= path
.substring(1);
349 dialog
.setFilterPath(path
);
351 } catch (IllegalArgumentException e1
) {
352 // ignore here, we just' don't set the directory in the
357 String result
= dialog
.open();
359 uriText
.setText("file:///" + result
); //$NON-NLS-1$
364 newLabel(g
, UIText
.RepositorySelectionPage_promptHost
+ ":"); //$NON-NLS-1$
365 hostText
= new Text(g
, SWT
.BORDER
);
366 GridDataFactory
.fillDefaults().span(2, 1).applyTo(hostText
);
367 hostText
.addModifyListener(new ModifyListener() {
368 public void modifyText(final ModifyEvent e
) {
369 setURI(uri
.setHost(nullString(hostText
.getText())));
373 newLabel(g
, UIText
.RepositorySelectionPage_promptPath
+ ":"); //$NON-NLS-1$
374 pathText
= new Text(g
, SWT
.BORDER
);
375 GridDataFactory
.fillDefaults().span(2, 1).applyTo(pathText
);
376 pathText
.addModifyListener(new ModifyListener() {
377 public void modifyText(final ModifyEvent e
) {
378 setURI(uri
.setPath(nullString(pathText
.getText())));
384 private Group
createAuthenticationGroup(final Composite parent
) {
385 final Group g
= createGroup(parent
,
386 UIText
.RepositorySelectionPage_groupAuthentication
);
388 newLabel(g
, UIText
.RepositorySelectionPage_promptUser
+ ":"); //$NON-NLS-1$
389 userText
= new Text(g
, SWT
.BORDER
);
390 userText
.setLayoutData(createFieldGridData());
391 userText
.addModifyListener(new ModifyListener() {
392 public void modifyText(final ModifyEvent e
) {
393 setURI(uri
.setUser(nullString(userText
.getText())));
397 newLabel(g
, UIText
.RepositorySelectionPage_promptPassword
+ ":"); //$NON-NLS-1$
398 passText
= new Text(g
, SWT
.BORDER
| SWT
.PASSWORD
);
399 passText
.setLayoutData(createFieldGridData());
403 private void createConnectionGroup(final Composite parent
) {
404 final Group g
= createGroup(parent
,
405 UIText
.RepositorySelectionPage_groupConnection
);
407 newLabel(g
, UIText
.RepositorySelectionPage_promptScheme
+ ":"); //$NON-NLS-1$
408 scheme
= new Combo(g
, SWT
.DROP_DOWN
| SWT
.READ_ONLY
);
409 scheme
.setItems(DEFAULT_SCHEMES
);
410 scheme
.addSelectionListener(new SelectionAdapter() {
411 public void widgetSelected(final SelectionEvent e
) {
412 final int idx
= scheme
.getSelectionIndex();
414 setURI(uri
.setScheme(null));
416 setURI(uri
.setScheme(nullString(scheme
.getItem(idx
))));
421 newLabel(g
, UIText
.RepositorySelectionPage_promptPort
+ ":"); //$NON-NLS-1$
422 portText
= new Text(g
, SWT
.BORDER
);
423 portText
.addVerifyListener(new VerifyListener() {
424 final Pattern p
= Pattern
.compile("^(?:[1-9][0-9]*)?$"); //$NON-NLS-1$
426 public void verifyText(final VerifyEvent e
) {
427 final String v
= portText
.getText();
429 v
.substring(0, e
.start
) + e
.text
+ v
.substring(e
.end
))
433 portText
.addModifyListener(new ModifyListener() {
434 public void modifyText(final ModifyEvent e
) {
435 final String val
= nullString(portText
.getText());
437 setURI(uri
.setPort(-1));
440 setURI(uri
.setPort(Integer
.parseInt(val
)));
441 } catch (NumberFormatException err
) {
442 // Ignore it for now.
449 private Group
createGroup(final Composite parent
, final String text
) {
450 final Group g
= new Group(parent
, SWT
.NONE
);
451 final GridLayout layout
= new GridLayout();
452 layout
.numColumns
= 2;
455 final GridData gd
= new GridData();
456 gd
.grabExcessHorizontalSpace
= true;
457 gd
.horizontalAlignment
= SWT
.FILL
;
462 private void newLabel(final Group g
, final String text
) {
463 new Label(g
, SWT
.NULL
).setText(text
);
466 private GridData
createFieldGridData() {
467 return new GridData(SWT
.FILL
, SWT
.DEFAULT
, true, false);
470 private boolean isGIT(final URIish uri
) {
471 return "git".equals(uri
.getScheme()); //$NON-NLS-1$
474 private boolean isFile(final URIish uri
) {
475 if ("file".equals(uri
.getScheme()) || uri
.getScheme() == null) //$NON-NLS-1$
477 if (uri
.getHost() != null || uri
.getPort() > 0 || uri
.getUser() != null
478 || uri
.getPass() != null || uri
.getPath() == null)
480 if (uri
.getScheme() == null)
481 return FS
.resolve(new File("."), uri
.getPath()).isDirectory(); //$NON-NLS-1$
485 private boolean isSSH(final URIish uri
) {
488 final String scheme
= uri
.getScheme();
489 if ("ssh".equals(scheme
)) //$NON-NLS-1$
491 if ("ssh+git".equals(scheme
)) //$NON-NLS-1$
493 if ("git+ssh".equals(scheme
)) //$NON-NLS-1$
495 if (scheme
== null && uri
.getHost() != null && uri
.getPath() != null)
500 private String
nullString(final String value
) {
503 final String v
= value
.trim();
504 return v
.length() == 0 ?
null : v
;
507 private void safeSet(final Text text
, final String value
) {
508 text
.setText(value
!= null ? value
: ""); //$NON-NLS-1$
511 private boolean isURISelected() {
512 return configuredRemotes
== null || presetUri
!= null
513 || uriButton
.getSelection();
516 private void setURI(final URIish u
) {
519 if (eventDepth
== 1) {
521 uriText
.setText(uri
.toString());
529 private List
<RemoteConfig
> getUsableConfigs(final List
<RemoteConfig
> remotes
) {
534 List
<RemoteConfig
> result
= new ArrayList
<RemoteConfig
>();
536 for (RemoteConfig config
: remotes
)
537 if ((sourceSelection
&& !config
.getURIs().isEmpty() || !sourceSelection
538 && (!config
.getPushURIs().isEmpty() || !config
.getURIs()
542 if (!result
.isEmpty())
548 private RemoteConfig
selectDefaultRemoteConfig() {
549 if (configuredRemotes
== null)
551 for (final RemoteConfig rc
: configuredRemotes
)
552 if (Constants
.DEFAULT_REMOTE_NAME
.equals(rc
.getName()))
554 return configuredRemotes
.get(0);
557 private String
getTextForRemoteConfig(final RemoteConfig rc
) {
558 final StringBuilder sb
= new StringBuilder(rc
.getName());
559 sb
.append(": "); //$NON-NLS-1$
560 boolean first
= true;
562 if (sourceSelection
) {
565 uris
= rc
.getPushURIs();
566 // if no push URIs are defined, use fetch URIs instead
567 if (uris
.isEmpty()) {
572 for (final URIish u
: uris
) {
573 final String uString
= u
.toString();
577 sb
.append(", "); //$NON-NLS-1$
578 if (sb
.length() + uString
.length() > REMOTE_CONFIG_TEXT_MAX_LENGTH
) {
579 sb
.append("..."); //$NON-NLS-1$
585 return sb
.toString();
588 private void checkPage() {
589 if (isURISelected()) {
591 if (uriText
.getText().length() == 0) {
592 selectionIncomplete(null);
597 final URIish finalURI
= new URIish(uriText
.getText());
598 String proto
= finalURI
.getScheme();
599 if (proto
== null && scheme
.getSelectionIndex() >= 0)
600 proto
= scheme
.getItem(scheme
.getSelectionIndex());
602 if (uri
.getPath() == null) {
603 selectionIncomplete(NLS
.bind(
604 UIText
.RepositorySelectionPage_fieldRequired
,
605 unamp(UIText
.RepositorySelectionPage_promptPath
),
610 if (isFile(finalURI
)) {
611 String badField
= null;
612 if (uri
.getHost() != null)
613 badField
= UIText
.RepositorySelectionPage_promptHost
;
614 else if (uri
.getUser() != null)
615 badField
= UIText
.RepositorySelectionPage_promptUser
;
616 else if (uri
.getPass() != null)
617 badField
= UIText
.RepositorySelectionPage_promptPassword
;
618 if (badField
!= null) {
619 selectionIncomplete(NLS
621 UIText
.RepositorySelectionPage_fieldNotSupported
,
622 unamp(badField
), proto
));
626 final File d
= FS
.resolve(new File("."), uri
.getPath()); //$NON-NLS-1$
628 selectionIncomplete(NLS
.bind(
629 UIText
.RepositorySelectionPage_fileNotFound
, d
630 .getAbsolutePath()));
634 selectionComplete(finalURI
, null);
638 if (uri
.getHost() == null) {
639 selectionIncomplete(NLS
.bind(
640 UIText
.RepositorySelectionPage_fieldRequired
,
641 unamp(UIText
.RepositorySelectionPage_promptHost
),
646 if (isGIT(finalURI
)) {
647 String badField
= null;
648 if (uri
.getUser() != null)
649 badField
= UIText
.RepositorySelectionPage_promptUser
;
650 else if (uri
.getPass() != null)
651 badField
= UIText
.RepositorySelectionPage_promptPassword
;
652 if (badField
!= null) {
653 selectionIncomplete(NLS
655 UIText
.RepositorySelectionPage_fieldNotSupported
,
656 unamp(badField
), proto
));
661 selectionComplete(finalURI
, null);
663 } catch (URISyntaxException e
) {
664 selectionIncomplete(e
.getReason());
666 } catch (Exception e
) {
667 Activator
.logError(NLS
.bind(
668 UIText
.RepositorySelectionPage_errorValidating
,
669 getClass().getName()),
671 selectionIncomplete(UIText
.RepositorySelectionPage_internalError
);
675 assert remoteButton
.getSelection();
676 selectionComplete(null, remoteConfig
);
681 private String
unamp(String s
) {
682 return s
.replace("&", ""); //$NON-NLS-1$ //$NON-NLS-2$
685 private void selectionIncomplete(final String errorMessage
) {
686 setExposedSelection(null, null);
687 setErrorMessage(errorMessage
);
688 setPageComplete(false);
691 private void selectionComplete(final URIish u
, final RemoteConfig rc
) {
692 setExposedSelection(u
, rc
);
693 setErrorMessage(null);
694 setPageComplete(true);
695 notifySelectionChanged();
698 private void setExposedSelection(final URIish u
, final RemoteConfig rc
) {
699 final RepositorySelection newSelection
= new RepositorySelection(u
, rc
);
700 if (newSelection
.equals(selection
))
703 selection
= newSelection
;
704 notifySelectionChanged();
707 private void updateRemoteAndURIPanels() {
708 setEnabledRecursively(uriPanel
, isURISelected());
709 if (uriPanel
.getEnabled())
711 if (configuredRemotes
!= null)
712 setEnabledRecursively(remotePanel
, !isURISelected());
715 private void updateAuthGroup() {
716 switch (scheme
.getSelectionIndex()) {
718 hostText
.setEnabled(true);
719 portText
.setEnabled(true);
720 setEnabledRecursively(authGroup
, false);
727 hostText
.setEnabled(true);
728 portText
.setEnabled(true);
729 setEnabledRecursively(authGroup
, true);
732 hostText
.setEnabled(false);
733 portText
.setEnabled(false);
734 setEnabledRecursively(authGroup
, false);
740 public void setVisible(boolean visible
) {
741 super.setVisible(visible
);
747 * Adds a URI string to the list of previously added ones
749 * TODO move this to some proper preferences handling class instead of
754 public static void saveUriInPrefs(String stringToAdd
) {
756 List
<String
> uriStrings
= getUrisFromPrefs();
758 if (uriStrings
.indexOf(stringToAdd
) == 0)
760 uriStrings
.add(0, stringToAdd
);
762 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
765 StringBuilder sb
= new StringBuilder();
766 StringBuilder lb
= new StringBuilder();
768 // there is no "good" separator for URIish, so we
769 // keep track of the URI lengths separately
770 for (String uriString
: uriStrings
) {
771 sb
.append(uriString
);
772 lb
.append(uriString
.length());
773 lb
.append(" "); //$NON-NLS-1$
775 prefs
.put(USED_URIS_PREF
, sb
.toString());
776 prefs
.put(USED_URIS_LENGTH_PREF
, lb
.toString());
780 } catch (BackingStoreException e
) {
781 // we simply ignore this here
786 * Gets the previously added URIs from the preferences
788 * TODO move this to some proper preferences handling class instead of
791 * @return a (possibly empty) list of URIs, never <code>null</code>
793 public static List
<String
> getUrisFromPrefs() {
795 // use a TreeSet to get the same sorting always
796 List
<String
> uriStrings
= new ArrayList
<String
>();
798 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
800 // since there is no "good" separator for URIish, so we
801 // keep track of the URI lengths separately
802 String uriLengths
= prefs
.get(USED_URIS_LENGTH_PREF
, ""); //$NON-NLS-1$
803 String uris
= prefs
.get(USED_URIS_PREF
, ""); //$NON-NLS-1$
805 StringTokenizer tok
= new StringTokenizer(uriLengths
, " "); //$NON-NLS-1$
807 while (tok
.hasMoreTokens()) {
809 int length
= Integer
.parseInt(tok
.nextToken());
810 if (uris
.length() >= (offset
+ length
)) {
811 uriStrings
.add(uris
.substring(offset
, offset
+ length
));
814 } catch (NumberFormatException nfe
) {
823 private void setEnabledRecursively(final Control control
,
824 final boolean enable
) {
825 control
.setEnabled(enable
);
826 if (control
instanceof Composite
)
827 for (final Control child
: ((Composite
) control
).getChildren())
828 setEnabledRecursively(child
, enable
);
831 private void addContentProposalToUriText(Text uriTextField
) {
833 UIUtils
.addBulbDecorator(uriTextField
, UIText
.RepositorySelectionPage_ShowPreviousURIs_HoverText
);
835 IContentProposalProvider cp
= new IContentProposalProvider() {
837 public IContentProposal
[] getProposals(String contents
, int position
) {
839 List
<IContentProposal
> resultList
= new ArrayList
<IContentProposal
>();
841 String patternString
= contents
;
842 while (patternString
.length() > 0
843 && patternString
.charAt(0) == ' ')
844 patternString
= patternString
.substring(1);
845 // make the simplest possible pattern check: allow "*"
846 // for multiple characters
847 patternString
= patternString
.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
848 // make sure we add a (logical) * at the end
849 if (!patternString
.endsWith(".*")) { //$NON-NLS-1$
850 patternString
= patternString
+ ".*"; //$NON-NLS-1$
852 // let's compile a case-insensitive pattern (assumes ASCII only)
855 pattern
= Pattern
.compile(patternString
,
856 Pattern
.CASE_INSENSITIVE
);
857 } catch (PatternSyntaxException e
) {
861 List
<String
> uriStrings
= getUrisFromPrefs();
862 for (final String uriString
: uriStrings
) {
865 && !pattern
.matcher(uriString
).matches())
868 IContentProposal propsal
= new IContentProposal() {
870 public String
getLabel() {
874 public String
getDescription() {
878 public int getCursorPosition() {
882 public String
getContent() {
886 resultList
.add(propsal
);
889 return resultList
.toArray(new IContentProposal
[resultList
894 // set the acceptance style to always replace the complete content
895 new ContentProposalAdapter(uriTextField
, new TextContentAdapter(), cp
,
897 .setProposalAcceptanceStyle(ContentProposalAdapter
.PROPOSAL_REPLACE
);
901 private void updateFields(final String text
) {
907 final URIish u
= new URIish(text
);
908 safeSet(hostText
, u
.getHost());
909 safeSet(pathText
, u
.getPath());
910 safeSet(userText
, u
.getUser());
911 safeSet(passText
, u
.getPass());
914 portText
.setText(Integer
.toString(u
.getPort()));
916 portText
.setText(""); //$NON-NLS-1$
919 scheme
.select(S_FILE
);
921 scheme
.select(S_SSH
);
923 for (int i
= 0; i
< DEFAULT_SCHEMES
.length
; i
++) {
924 if (DEFAULT_SCHEMES
[i
].equals(u
.getScheme())) {
933 } catch (URISyntaxException err
) {
934 // leave uriText as it is, but clean up underlying uri and
937 hostText
.setText(""); //$NON-NLS-1$
938 pathText
.setText(""); //$NON-NLS-1$
939 userText
.setText(""); //$NON-NLS-1$
940 passText
.setText(""); //$NON-NLS-1$
941 portText
.setText(""); //$NON-NLS-1$