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());
174 if(Transport
.canHandleProtocol(new URIish(text
))) {
177 } catch (URISyntaxException e
) {
181 this.presetUri
= preset
;
183 this.configuredRemotes
= getUsableConfigs(configuredRemotes
);
184 this.remoteConfig
= selectDefaultRemoteConfig();
186 selection
= RepositorySelection
.INVALID_SELECTION
;
188 if (sourceSelection
) {
189 setTitle(UIText
.RepositorySelectionPage_sourceSelectionTitle
);
190 setDescription(UIText
.RepositorySelectionPage_sourceSelectionDescription
);
192 setTitle(UIText
.RepositorySelectionPage_destinationSelectionTitle
);
193 setDescription(UIText
.RepositorySelectionPage_destinationSelectionDescription
);
198 * Create repository selection page, allowing user specifying URI, with no
199 * preconfigured remotes selection.
201 * @param sourceSelection
202 * true if dialog is used for source selection; false otherwise
203 * (destination selection). This indicates appropriate text
206 * the pre-set URI, may be null
208 public RepositorySelectionPage(final boolean sourceSelection
,
210 this(sourceSelection
, null, presetUri
);
214 * @return repository selection representing current page state.
216 public RepositorySelection
getSelection() {
221 * Compare current repository selection set by user to provided one.
224 * repository selection to compare.
225 * @return true if provided selection is equal to current page selection,
228 public boolean selectionEquals(final RepositorySelection s
) {
229 return selection
.equals(s
);
232 public void createControl(final Composite parent
) {
233 final Composite panel
= new Composite(parent
, SWT
.NULL
);
234 panel
.setLayout(new GridLayout());
236 if (configuredRemotes
!= null)
237 createRemotePanel(panel
);
239 createUriPanel(panel
);
241 if(presetUri
!= null)
242 updateFields(presetUri
);
244 updateRemoteAndURIPanels();
250 private void createRemotePanel(final Composite parent
) {
251 remoteButton
= new Button(parent
, SWT
.RADIO
);
253 .setText(UIText
.RepositorySelectionPage_configuredRemoteChoice
254 + ":"); //$NON-NLS-1$
255 remoteButton
.setSelection(true);
257 remotePanel
= new Composite(parent
, SWT
.NULL
);
258 remotePanel
.setLayout(new GridLayout());
259 final GridData gd
= new GridData();
260 gd
.grabExcessHorizontalSpace
= true;
261 gd
.horizontalAlignment
= SWT
.FILL
;
262 remotePanel
.setLayoutData(gd
);
264 remoteCombo
= new Combo(remotePanel
, SWT
.READ_ONLY
| SWT
.DROP_DOWN
);
265 final String items
[] = new String
[configuredRemotes
.size()];
267 for (final RemoteConfig rc
: configuredRemotes
)
268 items
[i
++] = getTextForRemoteConfig(rc
);
269 final int defaultIndex
= configuredRemotes
.indexOf(remoteConfig
);
270 remoteCombo
.setItems(items
);
271 remoteCombo
.select(defaultIndex
);
272 remoteCombo
.addSelectionListener(new SelectionAdapter() {
274 public void widgetSelected(SelectionEvent e
) {
275 final int idx
= remoteCombo
.getSelectionIndex();
276 remoteConfig
= configuredRemotes
.get(idx
);
282 private void createUriPanel(final Composite parent
) {
283 if (configuredRemotes
!= null) {
284 uriButton
= new Button(parent
, SWT
.RADIO
);
285 uriButton
.setText(UIText
.RepositorySelectionPage_uriChoice
+ ":"); //$NON-NLS-1$
286 uriButton
.addSelectionListener(new SelectionAdapter() {
287 public void widgetSelected(SelectionEvent e
) {
288 // occurs either on selection or unselection event
289 updateRemoteAndURIPanels();
295 uriPanel
= new Composite(parent
, SWT
.NULL
);
296 uriPanel
.setLayout(new GridLayout());
297 final GridData gd
= new GridData();
298 gd
.grabExcessHorizontalSpace
= true;
299 gd
.horizontalAlignment
= SWT
.FILL
;
300 uriPanel
.setLayoutData(gd
);
302 createLocationGroup(uriPanel
);
303 createConnectionGroup(uriPanel
);
304 authGroup
= createAuthenticationGroup(uriPanel
);
307 private void createLocationGroup(final Composite parent
) {
308 final Group g
= createGroup(parent
,
309 UIText
.RepositorySelectionPage_groupLocation
);
311 g
.setLayout(new GridLayout(3, false));
313 newLabel(g
, UIText
.RepositorySelectionPage_promptURI
+ ":"); //$NON-NLS-1$
314 uriText
= new Text(g
, SWT
.BORDER
);
316 if (presetUri
!= null)
317 uriText
.setText(presetUri
);
319 uriText
.setLayoutData(createFieldGridData());
320 uriText
.addModifyListener(new ModifyListener() {
321 public void modifyText(final ModifyEvent e
) {
322 updateFields(uriText
.getText());
326 addContentProposalToUriText(uriText
);
328 Button browseButton
= new Button(g
, SWT
.NULL
);
329 browseButton
.setText(UIText
.RepositorySelectionPage_BrowseLocalFile
);
330 browseButton
.addSelectionListener(new SelectionAdapter() {
333 public void widgetSelected(SelectionEvent e
) {
334 DirectoryDialog dialog
= new DirectoryDialog(getShell());
335 // if a file-uri was selected before, let's try to open
336 // the directory dialog on the same directory
337 if (!uriText
.getText().equals("")) { //$NON-NLS-1$
339 URI testUri
= URI
.create(uriText
.getText().replace(
341 if (testUri
.getScheme().equals("file")) { //$NON-NLS-1$
342 String path
= testUri
.getPath();
343 if (path
.length() > 1 && path
.startsWith("/")) //$NON-NLS-1$
344 path
= path
.substring(1);
346 dialog
.setFilterPath(path
);
348 } catch (IllegalArgumentException e1
) {
349 // ignore here, we just' don't set the directory in the
354 String result
= dialog
.open();
356 uriText
.setText("file:///" + result
); //$NON-NLS-1$
361 newLabel(g
, UIText
.RepositorySelectionPage_promptHost
+ ":"); //$NON-NLS-1$
362 hostText
= new Text(g
, SWT
.BORDER
);
363 GridDataFactory
.fillDefaults().span(2, 1).applyTo(hostText
);
364 hostText
.addModifyListener(new ModifyListener() {
365 public void modifyText(final ModifyEvent e
) {
366 setURI(uri
.setHost(nullString(hostText
.getText())));
370 newLabel(g
, UIText
.RepositorySelectionPage_promptPath
+ ":"); //$NON-NLS-1$
371 pathText
= new Text(g
, SWT
.BORDER
);
372 GridDataFactory
.fillDefaults().span(2, 1).applyTo(pathText
);
373 pathText
.addModifyListener(new ModifyListener() {
374 public void modifyText(final ModifyEvent e
) {
375 setURI(uri
.setPath(nullString(pathText
.getText())));
381 private Group
createAuthenticationGroup(final Composite parent
) {
382 final Group g
= createGroup(parent
,
383 UIText
.RepositorySelectionPage_groupAuthentication
);
385 newLabel(g
, UIText
.RepositorySelectionPage_promptUser
+ ":"); //$NON-NLS-1$
386 userText
= new Text(g
, SWT
.BORDER
);
387 userText
.setLayoutData(createFieldGridData());
388 userText
.addModifyListener(new ModifyListener() {
389 public void modifyText(final ModifyEvent e
) {
390 setURI(uri
.setUser(nullString(userText
.getText())));
394 newLabel(g
, UIText
.RepositorySelectionPage_promptPassword
+ ":"); //$NON-NLS-1$
395 passText
= new Text(g
, SWT
.BORDER
| SWT
.PASSWORD
);
396 passText
.setLayoutData(createFieldGridData());
400 private void createConnectionGroup(final Composite parent
) {
401 final Group g
= createGroup(parent
,
402 UIText
.RepositorySelectionPage_groupConnection
);
404 newLabel(g
, UIText
.RepositorySelectionPage_promptScheme
+ ":"); //$NON-NLS-1$
405 scheme
= new Combo(g
, SWT
.DROP_DOWN
| SWT
.READ_ONLY
);
406 scheme
.setItems(DEFAULT_SCHEMES
);
407 scheme
.addSelectionListener(new SelectionAdapter() {
408 public void widgetSelected(final SelectionEvent e
) {
409 final int idx
= scheme
.getSelectionIndex();
411 setURI(uri
.setScheme(null));
413 setURI(uri
.setScheme(nullString(scheme
.getItem(idx
))));
418 newLabel(g
, UIText
.RepositorySelectionPage_promptPort
+ ":"); //$NON-NLS-1$
419 portText
= new Text(g
, SWT
.BORDER
);
420 portText
.addVerifyListener(new VerifyListener() {
421 final Pattern p
= Pattern
.compile("^(?:[1-9][0-9]*)?$"); //$NON-NLS-1$
423 public void verifyText(final VerifyEvent e
) {
424 final String v
= portText
.getText();
426 v
.substring(0, e
.start
) + e
.text
+ v
.substring(e
.end
))
430 portText
.addModifyListener(new ModifyListener() {
431 public void modifyText(final ModifyEvent e
) {
432 final String val
= nullString(portText
.getText());
434 setURI(uri
.setPort(-1));
437 setURI(uri
.setPort(Integer
.parseInt(val
)));
438 } catch (NumberFormatException err
) {
439 // Ignore it for now.
446 private Group
createGroup(final Composite parent
, final String text
) {
447 final Group g
= new Group(parent
, SWT
.NONE
);
448 final GridLayout layout
= new GridLayout();
449 layout
.numColumns
= 2;
452 final GridData gd
= new GridData();
453 gd
.grabExcessHorizontalSpace
= true;
454 gd
.horizontalAlignment
= SWT
.FILL
;
459 private void newLabel(final Group g
, final String text
) {
460 new Label(g
, SWT
.NULL
).setText(text
);
463 private GridData
createFieldGridData() {
464 return new GridData(SWT
.FILL
, SWT
.DEFAULT
, true, false);
467 private boolean isGIT(final URIish uri
) {
468 return "git".equals(uri
.getScheme()); //$NON-NLS-1$
471 private boolean isFile(final URIish uri
) {
472 if ("file".equals(uri
.getScheme()) || uri
.getScheme() == null) //$NON-NLS-1$
474 if (uri
.getHost() != null || uri
.getPort() > 0 || uri
.getUser() != null
475 || uri
.getPass() != null || uri
.getPath() == null)
477 if (uri
.getScheme() == null)
478 return FS
.resolve(new File("."), uri
.getPath()).isDirectory(); //$NON-NLS-1$
482 private boolean isSSH(final URIish uri
) {
485 final String scheme
= uri
.getScheme();
486 if ("ssh".equals(scheme
)) //$NON-NLS-1$
488 if ("ssh+git".equals(scheme
)) //$NON-NLS-1$
490 if ("git+ssh".equals(scheme
)) //$NON-NLS-1$
492 if (scheme
== null && uri
.getHost() != null && uri
.getPath() != null)
497 private String
nullString(final String value
) {
500 final String v
= value
.trim();
501 return v
.length() == 0 ?
null : v
;
504 private void safeSet(final Text text
, final String value
) {
505 text
.setText(value
!= null ? value
: ""); //$NON-NLS-1$
508 private boolean isURISelected() {
509 return configuredRemotes
== null || presetUri
!= null
510 || uriButton
.getSelection();
513 private void setURI(final URIish u
) {
516 if (eventDepth
== 1) {
518 uriText
.setText(uri
.toString());
526 private List
<RemoteConfig
> getUsableConfigs(final List
<RemoteConfig
> remotes
) {
531 List
<RemoteConfig
> result
= new ArrayList
<RemoteConfig
>();
533 for (RemoteConfig config
: remotes
)
534 if ((sourceSelection
&& !config
.getURIs().isEmpty() || !sourceSelection
535 && (!config
.getPushURIs().isEmpty() || !config
.getURIs()
539 if (!result
.isEmpty())
545 private RemoteConfig
selectDefaultRemoteConfig() {
546 if (configuredRemotes
== null)
548 for (final RemoteConfig rc
: configuredRemotes
)
549 if (Constants
.DEFAULT_REMOTE_NAME
.equals(rc
.getName()))
551 return configuredRemotes
.get(0);
554 private String
getTextForRemoteConfig(final RemoteConfig rc
) {
555 final StringBuilder sb
= new StringBuilder(rc
.getName());
556 sb
.append(": "); //$NON-NLS-1$
557 boolean first
= true;
559 if (sourceSelection
) {
562 uris
= rc
.getPushURIs();
563 // if no push URIs are defined, use fetch URIs instead
564 if (uris
.isEmpty()) {
569 for (final URIish u
: uris
) {
570 final String uString
= u
.toString();
574 sb
.append(", "); //$NON-NLS-1$
575 if (sb
.length() + uString
.length() > REMOTE_CONFIG_TEXT_MAX_LENGTH
) {
576 sb
.append("..."); //$NON-NLS-1$
582 return sb
.toString();
585 private void checkPage() {
586 if (isURISelected()) {
588 if (uriText
.getText().length() == 0) {
589 selectionIncomplete(null);
594 final URIish finalURI
= new URIish(uriText
.getText());
595 String proto
= finalURI
.getScheme();
596 if (proto
== null && scheme
.getSelectionIndex() >= 0)
597 proto
= scheme
.getItem(scheme
.getSelectionIndex());
599 if (uri
.getPath() == null) {
600 selectionIncomplete(NLS
.bind(
601 UIText
.RepositorySelectionPage_fieldRequired
,
602 unamp(UIText
.RepositorySelectionPage_promptPath
),
607 if (isFile(finalURI
)) {
608 String badField
= null;
609 if (uri
.getHost() != null)
610 badField
= UIText
.RepositorySelectionPage_promptHost
;
611 else if (uri
.getUser() != null)
612 badField
= UIText
.RepositorySelectionPage_promptUser
;
613 else if (uri
.getPass() != null)
614 badField
= UIText
.RepositorySelectionPage_promptPassword
;
615 if (badField
!= null) {
616 selectionIncomplete(NLS
618 UIText
.RepositorySelectionPage_fieldNotSupported
,
619 unamp(badField
), proto
));
623 final File d
= FS
.resolve(new File("."), uri
.getPath()); //$NON-NLS-1$
625 selectionIncomplete(NLS
.bind(
626 UIText
.RepositorySelectionPage_fileNotFound
, d
627 .getAbsolutePath()));
631 selectionComplete(finalURI
, null);
635 if (uri
.getHost() == null) {
636 selectionIncomplete(NLS
.bind(
637 UIText
.RepositorySelectionPage_fieldRequired
,
638 unamp(UIText
.RepositorySelectionPage_promptHost
),
643 if (isGIT(finalURI
)) {
644 String badField
= null;
645 if (uri
.getUser() != null)
646 badField
= UIText
.RepositorySelectionPage_promptUser
;
647 else if (uri
.getPass() != null)
648 badField
= UIText
.RepositorySelectionPage_promptPassword
;
649 if (badField
!= null) {
650 selectionIncomplete(NLS
652 UIText
.RepositorySelectionPage_fieldNotSupported
,
653 unamp(badField
), proto
));
658 selectionComplete(finalURI
, null);
660 } catch (URISyntaxException e
) {
661 selectionIncomplete(e
.getReason());
663 } catch (Exception e
) {
664 Activator
.logError(NLS
.bind(
665 UIText
.RepositorySelectionPage_errorValidating
,
666 getClass().getName()),
668 selectionIncomplete(UIText
.RepositorySelectionPage_internalError
);
672 assert remoteButton
.getSelection();
673 selectionComplete(null, remoteConfig
);
678 private String
unamp(String s
) {
679 return s
.replace("&", ""); //$NON-NLS-1$ //$NON-NLS-2$
682 private void selectionIncomplete(final String errorMessage
) {
683 setExposedSelection(null, null);
684 setErrorMessage(errorMessage
);
685 setPageComplete(false);
688 private void selectionComplete(final URIish u
, final RemoteConfig rc
) {
689 setExposedSelection(u
, rc
);
690 setErrorMessage(null);
691 setPageComplete(true);
692 notifySelectionChanged();
695 private void setExposedSelection(final URIish u
, final RemoteConfig rc
) {
696 final RepositorySelection newSelection
= new RepositorySelection(u
, rc
);
697 if (newSelection
.equals(selection
))
700 selection
= newSelection
;
701 notifySelectionChanged();
704 private void updateRemoteAndURIPanels() {
705 setEnabledRecursively(uriPanel
, isURISelected());
706 if (uriPanel
.getEnabled())
708 if (configuredRemotes
!= null)
709 setEnabledRecursively(remotePanel
, !isURISelected());
712 private void updateAuthGroup() {
713 switch (scheme
.getSelectionIndex()) {
715 hostText
.setEnabled(true);
716 portText
.setEnabled(true);
717 setEnabledRecursively(authGroup
, false);
724 hostText
.setEnabled(true);
725 portText
.setEnabled(true);
726 setEnabledRecursively(authGroup
, true);
729 hostText
.setEnabled(false);
730 portText
.setEnabled(false);
731 setEnabledRecursively(authGroup
, false);
737 public void setVisible(boolean visible
) {
738 super.setVisible(visible
);
744 * Adds a URI string to the list of previously added ones
746 * TODO move this to some proper preferences handling class instead of
751 public static void saveUriInPrefs(String stringToAdd
) {
753 List
<String
> uriStrings
= getUrisFromPrefs();
755 if (uriStrings
.indexOf(stringToAdd
) == 0)
757 uriStrings
.add(0, stringToAdd
);
759 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
762 StringBuilder sb
= new StringBuilder();
763 StringBuilder lb
= new StringBuilder();
765 // there is no "good" separator for URIish, so we
766 // keep track of the URI lengths separately
767 for (String uriString
: uriStrings
) {
768 sb
.append(uriString
);
769 lb
.append(uriString
.length());
770 lb
.append(" "); //$NON-NLS-1$
772 prefs
.put(USED_URIS_PREF
, sb
.toString());
773 prefs
.put(USED_URIS_LENGTH_PREF
, lb
.toString());
777 } catch (BackingStoreException e
) {
778 // we simply ignore this here
783 * Gets the previously added URIs from the preferences
785 * TODO move this to some proper preferences handling class instead of
788 * @return a (possibly empty) list of URIs, never <code>null</code>
790 public static List
<String
> getUrisFromPrefs() {
792 // use a TreeSet to get the same sorting always
793 List
<String
> uriStrings
= new ArrayList
<String
>();
795 IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
797 // since there is no "good" separator for URIish, so we
798 // keep track of the URI lengths separately
799 String uriLengths
= prefs
.get(USED_URIS_LENGTH_PREF
, ""); //$NON-NLS-1$
800 String uris
= prefs
.get(USED_URIS_PREF
, ""); //$NON-NLS-1$
802 StringTokenizer tok
= new StringTokenizer(uriLengths
, " "); //$NON-NLS-1$
804 while (tok
.hasMoreTokens()) {
806 int length
= Integer
.parseInt(tok
.nextToken());
807 if (uris
.length() >= (offset
+ length
)) {
808 uriStrings
.add(uris
.substring(offset
, offset
+ length
));
811 } catch (NumberFormatException nfe
) {
820 private void setEnabledRecursively(final Control control
,
821 final boolean enable
) {
822 control
.setEnabled(enable
);
823 if (control
instanceof Composite
)
824 for (final Control child
: ((Composite
) control
).getChildren())
825 setEnabledRecursively(child
, enable
);
828 private void addContentProposalToUriText(Text uriTextField
) {
830 UIUtils
.addBulbDecorator(uriTextField
, UIText
.RepositorySelectionPage_ShowPreviousURIs_HoverText
);
832 IContentProposalProvider cp
= new IContentProposalProvider() {
834 public IContentProposal
[] getProposals(String contents
, int position
) {
836 List
<IContentProposal
> resultList
= new ArrayList
<IContentProposal
>();
838 String patternString
= contents
;
839 while (patternString
.length() > 0
840 && patternString
.charAt(0) == ' ')
841 patternString
= patternString
.substring(1);
842 // make the simplest possible pattern check: allow "*"
843 // for multiple characters
844 patternString
= patternString
.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
845 // make sure we add a (logical) * at the end
846 if (!patternString
.endsWith(".*")) { //$NON-NLS-1$
847 patternString
= patternString
+ ".*"; //$NON-NLS-1$
849 // let's compile a case-insensitive pattern (assumes ASCII only)
852 pattern
= Pattern
.compile(patternString
,
853 Pattern
.CASE_INSENSITIVE
);
854 } catch (PatternSyntaxException e
) {
858 List
<String
> uriStrings
= getUrisFromPrefs();
859 for (final String uriString
: uriStrings
) {
862 && !pattern
.matcher(uriString
).matches())
865 IContentProposal propsal
= new IContentProposal() {
867 public String
getLabel() {
871 public String
getDescription() {
875 public int getCursorPosition() {
879 public String
getContent() {
883 resultList
.add(propsal
);
886 return resultList
.toArray(new IContentProposal
[resultList
891 // set the acceptance style to always replace the complete content
892 new ContentProposalAdapter(uriTextField
, new TextContentAdapter(), cp
,
894 .setProposalAcceptanceStyle(ContentProposalAdapter
.PROPOSAL_REPLACE
);
898 private void updateFields(final String text
) {
904 final URIish u
= new URIish(text
);
905 safeSet(hostText
, u
.getHost());
906 safeSet(pathText
, u
.getPath());
907 safeSet(userText
, u
.getUser());
908 safeSet(passText
, u
.getPass());
911 portText
.setText(Integer
.toString(u
.getPort()));
913 portText
.setText(""); //$NON-NLS-1$
916 scheme
.select(S_FILE
);
918 scheme
.select(S_SSH
);
920 for (int i
= 0; i
< DEFAULT_SCHEMES
.length
; i
++) {
921 if (DEFAULT_SCHEMES
[i
].equals(u
.getScheme())) {
930 } catch (URISyntaxException err
) {
931 // leave uriText as it is, but clean up underlying uri and
934 hostText
.setText(""); //$NON-NLS-1$
935 pathText
.setText(""); //$NON-NLS-1$
936 userText
.setText(""); //$NON-NLS-1$
937 passText
.setText(""); //$NON-NLS-1$
938 portText
.setText(""); //$NON-NLS-1$