Missing Push URI
[egit.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / components / RepositorySelectionPage.java
blobe080a5f10cce6b9287d4893850a879275691b649
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;
14 import java.io.File;
15 import java.net.URI;
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.URIish;
36 import org.eclipse.jgit.util.FS;
37 import org.eclipse.osgi.util.NLS;
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.events.ModifyEvent;
40 import org.eclipse.swt.events.ModifyListener;
41 import org.eclipse.swt.events.SelectionAdapter;
42 import org.eclipse.swt.events.SelectionEvent;
43 import org.eclipse.swt.events.VerifyEvent;
44 import org.eclipse.swt.events.VerifyListener;
45 import org.eclipse.swt.layout.GridData;
46 import org.eclipse.swt.layout.GridLayout;
47 import org.eclipse.swt.widgets.Button;
48 import org.eclipse.swt.widgets.Combo;
49 import org.eclipse.swt.widgets.Composite;
50 import org.eclipse.swt.widgets.Control;
51 import org.eclipse.swt.widgets.DirectoryDialog;
52 import org.eclipse.swt.widgets.Group;
53 import org.eclipse.swt.widgets.Label;
54 import org.eclipse.swt.widgets.Text;
55 import org.osgi.service.prefs.BackingStoreException;
57 /**
58 * Wizard page that allows the user entering the location of a remote repository
59 * by specifying URL manually or selecting a preconfigured remote repository.
61 public class RepositorySelectionPage extends BaseWizardPage {
63 private final static String USED_URIS_PREF = "RepositorySelectionPage.UsedUris"; //$NON-NLS-1$
65 private final static String USED_URIS_LENGTH_PREF = "RepositorySelectionPage.UsedUrisLength"; //$NON-NLS-1$
67 private static final int REMOTE_CONFIG_TEXT_MAX_LENGTH = 80;
69 private static final int S_GIT = 0;
71 private static final int S_SSH = 1;
73 private static final int S_SFTP = 2;
75 private static final int S_HTTP = 3;
77 private static final int S_HTTPS = 4;
79 private static final int S_FTP = 5;
81 private static final int S_FILE = 6;
83 private static final String[] DEFAULT_SCHEMES;
85 static {
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 final List<RemoteConfig> configuredRemotes;
98 private final boolean sourceSelection;
100 private final String presetUri;
102 private Group authGroup;
104 private Text uriText;
106 private Text hostText;
108 private Text pathText;
110 private Text userText;
112 private Text passText;
114 private Combo scheme;
116 private Text portText;
118 private int eventDepth;
120 private URIish uri;
122 private RemoteConfig remoteConfig;
124 private RepositorySelection selection;
126 private Composite remotePanel;
128 private Button remoteButton;
130 private Combo remoteCombo;
132 private Composite uriPanel;
134 private Button uriButton;
137 * Create repository selection page, allowing user specifying URI or
138 * (optionally) choosing from preconfigured remotes list.
139 * <p>
140 * Wizard page is created without image, just with text description.
142 * @param sourceSelection
143 * true if dialog is used for source selection; false otherwise
144 * (destination selection). This indicates appropriate text
145 * messages.
146 * @param configuredRemotes
147 * list of configured remotes that user may select as an
148 * alternative to manual URI specification. Remotes appear in
149 * given order in GUI, with
150 * {@value Constants#DEFAULT_REMOTE_NAME} as the default choice.
151 * List may be null or empty - no remotes configurations appear
152 * in this case. Note that the provided list may be changed by
153 * this constructor.
154 * @param presetUri
155 * the pre-set URI, may be null
157 public RepositorySelectionPage(final boolean sourceSelection,
158 final List<RemoteConfig> configuredRemotes, String presetUri) {
160 super(RepositorySelectionPage.class.getName());
162 this.uri = new URIish();
163 this.sourceSelection = sourceSelection;
164 this.presetUri = presetUri;
166 this.configuredRemotes = getUsableConfigs(configuredRemotes);
167 this.remoteConfig = selectDefaultRemoteConfig();
169 selection = RepositorySelection.INVALID_SELECTION;
171 if (sourceSelection) {
172 setTitle(UIText.RepositorySelectionPage_sourceSelectionTitle);
173 setDescription(UIText.RepositorySelectionPage_sourceSelectionDescription);
174 } else {
175 setTitle(UIText.RepositorySelectionPage_destinationSelectionTitle);
176 setDescription(UIText.RepositorySelectionPage_destinationSelectionDescription);
181 * Create repository selection page, allowing user specifying URI, with no
182 * preconfigured remotes selection.
184 * @param sourceSelection
185 * true if dialog is used for source selection; false otherwise
186 * (destination selection). This indicates appropriate text
187 * messages.
188 * @param presetUri
189 * the pre-set URI, may be null
191 public RepositorySelectionPage(final boolean sourceSelection,
192 String presetUri) {
193 this(sourceSelection, null, presetUri);
197 * @return repository selection representing current page state.
199 public RepositorySelection getSelection() {
200 return selection;
204 * Compare current repository selection set by user to provided one.
206 * @param s
207 * repository selection to compare.
208 * @return true if provided selection is equal to current page selection,
209 * false otherwise.
211 public boolean selectionEquals(final RepositorySelection s) {
212 return selection.equals(s);
215 public void createControl(final Composite parent) {
216 final Composite panel = new Composite(parent, SWT.NULL);
217 panel.setLayout(new GridLayout());
219 if (configuredRemotes != null)
220 createRemotePanel(panel);
222 createUriPanel(panel);
224 updateRemoteAndURIPanels();
225 setControl(panel);
227 checkPage();
230 private void createRemotePanel(final Composite parent) {
231 remoteButton = new Button(parent, SWT.RADIO);
232 remoteButton
233 .setText(UIText.RepositorySelectionPage_configuredRemoteChoice
234 + ":"); //$NON-NLS-1$
235 remoteButton.setSelection(true);
237 remotePanel = new Composite(parent, SWT.NULL);
238 remotePanel.setLayout(new GridLayout());
239 final GridData gd = new GridData();
240 gd.grabExcessHorizontalSpace = true;
241 gd.horizontalAlignment = SWT.FILL;
242 remotePanel.setLayoutData(gd);
244 remoteCombo = new Combo(remotePanel, SWT.READ_ONLY | SWT.DROP_DOWN);
245 final String items[] = new String[configuredRemotes.size()];
246 int i = 0;
247 for (final RemoteConfig rc : configuredRemotes)
248 items[i++] = getTextForRemoteConfig(rc);
249 final int defaultIndex = configuredRemotes.indexOf(remoteConfig);
250 remoteCombo.setItems(items);
251 remoteCombo.select(defaultIndex);
252 remoteCombo.addSelectionListener(new SelectionAdapter() {
253 @Override
254 public void widgetSelected(SelectionEvent e) {
255 final int idx = remoteCombo.getSelectionIndex();
256 remoteConfig = configuredRemotes.get(idx);
257 checkPage();
262 private void createUriPanel(final Composite parent) {
263 if (configuredRemotes != null) {
264 uriButton = new Button(parent, SWT.RADIO);
265 uriButton.setText(UIText.RepositorySelectionPage_uriChoice + ":"); //$NON-NLS-1$
266 uriButton.addSelectionListener(new SelectionAdapter() {
267 public void widgetSelected(SelectionEvent e) {
268 // occurs either on selection or unselection event
269 updateRemoteAndURIPanels();
270 checkPage();
275 uriPanel = new Composite(parent, SWT.NULL);
276 uriPanel.setLayout(new GridLayout());
277 final GridData gd = new GridData();
278 gd.grabExcessHorizontalSpace = true;
279 gd.horizontalAlignment = SWT.FILL;
280 uriPanel.setLayoutData(gd);
282 createLocationGroup(uriPanel);
283 createConnectionGroup(uriPanel);
284 authGroup = createAuthenticationGroup(uriPanel);
287 private void createLocationGroup(final Composite parent) {
288 final Group g = createGroup(parent,
289 UIText.RepositorySelectionPage_groupLocation);
291 g.setLayout(new GridLayout(3, false));
293 newLabel(g, UIText.RepositorySelectionPage_promptURI + ":"); //$NON-NLS-1$
294 uriText = new Text(g, SWT.BORDER);
296 if (presetUri != null)
297 uriText.setText(presetUri);
299 uriText.setLayoutData(createFieldGridData());
300 uriText.addModifyListener(new ModifyListener() {
301 public void modifyText(final ModifyEvent e) {
302 try {
303 eventDepth++;
304 if (eventDepth != 1)
305 return;
307 final URIish u = new URIish(uriText.getText());
308 safeSet(hostText, u.getHost());
309 safeSet(pathText, u.getPath());
310 safeSet(userText, u.getUser());
311 safeSet(passText, u.getPass());
313 if (u.getPort() > 0)
314 portText.setText(Integer.toString(u.getPort()));
315 else
316 portText.setText(""); //$NON-NLS-1$
318 if (isFile(u))
319 scheme.select(S_FILE);
320 else if (isSSH(u))
321 scheme.select(S_SSH);
322 else {
323 for (int i = 0; i < DEFAULT_SCHEMES.length; i++) {
324 if (DEFAULT_SCHEMES[i].equals(u.getScheme())) {
325 scheme.select(i);
326 break;
331 updateAuthGroup();
332 uri = u;
333 } catch (URISyntaxException err) {
334 // leave uriText as it is, but clean up underlying uri and
335 // decomposed fields
336 uri = new URIish();
337 hostText.setText(""); //$NON-NLS-1$
338 pathText.setText(""); //$NON-NLS-1$
339 userText.setText(""); //$NON-NLS-1$
340 passText.setText(""); //$NON-NLS-1$
341 portText.setText(""); //$NON-NLS-1$
342 scheme.select(0);
343 } finally {
344 eventDepth--;
346 checkPage();
350 addContentProposalToUriText(uriText);
352 Button browseButton = new Button(g, SWT.NULL);
353 browseButton.setText(UIText.RepositorySelectionPage_BrowseLocalFile);
354 browseButton.addSelectionListener(new SelectionAdapter() {
356 @Override
357 public void widgetSelected(SelectionEvent e) {
358 DirectoryDialog dialog = new DirectoryDialog(getShell());
359 // if a file-uri was selected before, let's try to open
360 // the directory dialog on the same directory
361 if (!uriText.getText().equals("")) { //$NON-NLS-1$
362 try {
363 URI testUri = URI.create(uriText.getText().replace(
364 '\\', '/'));
365 if (testUri.getScheme().equals("file")) { //$NON-NLS-1$
366 String path = testUri.getPath();
367 if (path.length() > 1 && path.startsWith("/")) //$NON-NLS-1$
368 path = path.substring(1);
370 dialog.setFilterPath(path);
372 } catch (IllegalArgumentException e1) {
373 // ignore here, we just' don't set the directory in the
374 // browser
378 String result = dialog.open();
379 if (result != null)
380 uriText.setText("file:///" + result); //$NON-NLS-1$
385 newLabel(g, UIText.RepositorySelectionPage_promptHost + ":"); //$NON-NLS-1$
386 hostText = new Text(g, SWT.BORDER);
387 GridDataFactory.fillDefaults().span(2, 1).applyTo(hostText);
388 hostText.addModifyListener(new ModifyListener() {
389 public void modifyText(final ModifyEvent e) {
390 setURI(uri.setHost(nullString(hostText.getText())));
394 newLabel(g, UIText.RepositorySelectionPage_promptPath + ":"); //$NON-NLS-1$
395 pathText = new Text(g, SWT.BORDER);
396 GridDataFactory.fillDefaults().span(2, 1).applyTo(pathText);
397 pathText.addModifyListener(new ModifyListener() {
398 public void modifyText(final ModifyEvent e) {
399 setURI(uri.setPath(nullString(pathText.getText())));
404 private Group createAuthenticationGroup(final Composite parent) {
405 final Group g = createGroup(parent,
406 UIText.RepositorySelectionPage_groupAuthentication);
408 newLabel(g, UIText.RepositorySelectionPage_promptUser + ":"); //$NON-NLS-1$
409 userText = new Text(g, SWT.BORDER);
410 userText.setLayoutData(createFieldGridData());
411 userText.addModifyListener(new ModifyListener() {
412 public void modifyText(final ModifyEvent e) {
413 setURI(uri.setUser(nullString(userText.getText())));
417 newLabel(g, UIText.RepositorySelectionPage_promptPassword + ":"); //$NON-NLS-1$
418 passText = new Text(g, SWT.BORDER | SWT.PASSWORD);
419 passText.setLayoutData(createFieldGridData());
420 return g;
423 private void createConnectionGroup(final Composite parent) {
424 final Group g = createGroup(parent,
425 UIText.RepositorySelectionPage_groupConnection);
427 newLabel(g, UIText.RepositorySelectionPage_promptScheme + ":"); //$NON-NLS-1$
428 scheme = new Combo(g, SWT.DROP_DOWN | SWT.READ_ONLY);
429 scheme.setItems(DEFAULT_SCHEMES);
430 scheme.addSelectionListener(new SelectionAdapter() {
431 public void widgetSelected(final SelectionEvent e) {
432 final int idx = scheme.getSelectionIndex();
433 if (idx < 0)
434 setURI(uri.setScheme(null));
435 else
436 setURI(uri.setScheme(nullString(scheme.getItem(idx))));
437 updateAuthGroup();
441 newLabel(g, UIText.RepositorySelectionPage_promptPort + ":"); //$NON-NLS-1$
442 portText = new Text(g, SWT.BORDER);
443 portText.addVerifyListener(new VerifyListener() {
444 final Pattern p = Pattern.compile("^(?:[1-9][0-9]*)?$"); //$NON-NLS-1$
446 public void verifyText(final VerifyEvent e) {
447 final String v = portText.getText();
448 e.doit = p.matcher(
449 v.substring(0, e.start) + e.text + v.substring(e.end))
450 .matches();
453 portText.addModifyListener(new ModifyListener() {
454 public void modifyText(final ModifyEvent e) {
455 final String val = nullString(portText.getText());
456 if (val == null)
457 setURI(uri.setPort(-1));
458 else {
459 try {
460 setURI(uri.setPort(Integer.parseInt(val)));
461 } catch (NumberFormatException err) {
462 // Ignore it for now.
469 private Group createGroup(final Composite parent, final String text) {
470 final Group g = new Group(parent, SWT.NONE);
471 final GridLayout layout = new GridLayout();
472 layout.numColumns = 2;
473 g.setLayout(layout);
474 g.setText(text);
475 final GridData gd = new GridData();
476 gd.grabExcessHorizontalSpace = true;
477 gd.horizontalAlignment = SWT.FILL;
478 g.setLayoutData(gd);
479 return g;
482 private void newLabel(final Group g, final String text) {
483 new Label(g, SWT.NULL).setText(text);
486 private GridData createFieldGridData() {
487 return new GridData(SWT.FILL, SWT.DEFAULT, true, false);
490 private boolean isGIT(final URIish uri) {
491 return "git".equals(uri.getScheme()); //$NON-NLS-1$
494 private boolean isFile(final URIish uri) {
495 if ("file".equals(uri.getScheme()) || uri.getScheme() == null) //$NON-NLS-1$
496 return true;
497 if (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null
498 || uri.getPass() != null || uri.getPath() == null)
499 return false;
500 if (uri.getScheme() == null)
501 return FS.resolve(new File("."), uri.getPath()).isDirectory(); //$NON-NLS-1$
502 return false;
505 private boolean isSSH(final URIish uri) {
506 if (!uri.isRemote())
507 return false;
508 final String scheme = uri.getScheme();
509 if ("ssh".equals(scheme)) //$NON-NLS-1$
510 return true;
511 if ("ssh+git".equals(scheme)) //$NON-NLS-1$
512 return true;
513 if ("git+ssh".equals(scheme)) //$NON-NLS-1$
514 return true;
515 if (scheme == null && uri.getHost() != null && uri.getPath() != null)
516 return true;
517 return false;
520 private String nullString(final String value) {
521 if (value == null)
522 return null;
523 final String v = value.trim();
524 return v.length() == 0 ? null : v;
527 private void safeSet(final Text text, final String value) {
528 text.setText(value != null ? value : ""); //$NON-NLS-1$
531 private boolean isURISelected() {
532 return configuredRemotes == null || presetUri != null
533 || uriButton.getSelection();
536 private void setURI(final URIish u) {
537 try {
538 eventDepth++;
539 if (eventDepth == 1) {
540 uri = u;
541 uriText.setText(uri.toString());
542 checkPage();
544 } finally {
545 eventDepth--;
549 private List<RemoteConfig> getUsableConfigs(final List<RemoteConfig> remotes) {
551 if (remotes == null)
552 return null;
554 List<RemoteConfig> result = new ArrayList<RemoteConfig>();
556 for (RemoteConfig config : remotes)
557 if ((sourceSelection && !config.getURIs().isEmpty() || !sourceSelection
558 && (!config.getPushURIs().isEmpty() || !config.getURIs()
559 .isEmpty())))
560 result.add(config);
562 if (!result.isEmpty())
563 return result;
565 return null;
568 private RemoteConfig selectDefaultRemoteConfig() {
569 if (configuredRemotes == null)
570 return null;
571 for (final RemoteConfig rc : configuredRemotes)
572 if (Constants.DEFAULT_REMOTE_NAME.equals(rc.getName()))
573 return rc;
574 return configuredRemotes.get(0);
577 private String getTextForRemoteConfig(final RemoteConfig rc) {
578 final StringBuilder sb = new StringBuilder(rc.getName());
579 sb.append(": "); //$NON-NLS-1$
580 boolean first = true;
581 List<URIish> uris;
582 if (sourceSelection) {
583 uris = rc.getURIs();
584 } else {
585 uris = rc.getPushURIs();
586 // if no push URIs are defined, use fetch URIs instead
587 if (uris.isEmpty()) {
588 uris = rc.getURIs();
592 for (final URIish u : uris) {
593 final String uString = u.toString();
594 if (first)
595 first = false;
596 else {
597 sb.append(", "); //$NON-NLS-1$
598 if (sb.length() + uString.length() > REMOTE_CONFIG_TEXT_MAX_LENGTH) {
599 sb.append("..."); //$NON-NLS-1$
600 break;
603 sb.append(uString);
605 return sb.toString();
608 private void checkPage() {
609 if (isURISelected()) {
610 assert uri != null;
611 if (uriText.getText().length() == 0) {
612 selectionIncomplete(null);
613 return;
616 try {
617 final URIish finalURI = new URIish(uriText.getText());
618 String proto = finalURI.getScheme();
619 if (proto == null && scheme.getSelectionIndex() >= 0)
620 proto = scheme.getItem(scheme.getSelectionIndex());
622 if (uri.getPath() == null) {
623 selectionIncomplete(NLS.bind(
624 UIText.RepositorySelectionPage_fieldRequired,
625 unamp(UIText.RepositorySelectionPage_promptPath),
626 proto));
627 return;
630 if (isFile(finalURI)) {
631 String badField = null;
632 if (uri.getHost() != null)
633 badField = UIText.RepositorySelectionPage_promptHost;
634 else if (uri.getUser() != null)
635 badField = UIText.RepositorySelectionPage_promptUser;
636 else if (uri.getPass() != null)
637 badField = UIText.RepositorySelectionPage_promptPassword;
638 if (badField != null) {
639 selectionIncomplete(NLS
640 .bind(
641 UIText.RepositorySelectionPage_fieldNotSupported,
642 unamp(badField), proto));
643 return;
646 final File d = FS.resolve(new File("."), uri.getPath()); //$NON-NLS-1$
647 if (!d.exists()) {
648 selectionIncomplete(NLS.bind(
649 UIText.RepositorySelectionPage_fileNotFound, d
650 .getAbsolutePath()));
651 return;
654 selectionComplete(finalURI, null);
655 return;
658 if (uri.getHost() == null) {
659 selectionIncomplete(NLS.bind(
660 UIText.RepositorySelectionPage_fieldRequired,
661 unamp(UIText.RepositorySelectionPage_promptHost),
662 proto));
663 return;
666 if (isGIT(finalURI)) {
667 String badField = null;
668 if (uri.getUser() != null)
669 badField = UIText.RepositorySelectionPage_promptUser;
670 else if (uri.getPass() != null)
671 badField = UIText.RepositorySelectionPage_promptPassword;
672 if (badField != null) {
673 selectionIncomplete(NLS
674 .bind(
675 UIText.RepositorySelectionPage_fieldNotSupported,
676 unamp(badField), proto));
677 return;
681 selectionComplete(finalURI, null);
682 return;
683 } catch (URISyntaxException e) {
684 selectionIncomplete(e.getReason());
685 return;
686 } catch (Exception e) {
687 Activator.logError(NLS.bind(
688 UIText.RepositorySelectionPage_errorValidating,
689 getClass().getName()),
691 selectionIncomplete(UIText.RepositorySelectionPage_internalError);
692 return;
694 } else {
695 assert remoteButton.getSelection();
696 selectionComplete(null, remoteConfig);
697 return;
701 private String unamp(String s) {
702 return s.replace("&", ""); //$NON-NLS-1$ //$NON-NLS-2$
705 private void selectionIncomplete(final String errorMessage) {
706 setExposedSelection(null, null);
707 setErrorMessage(errorMessage);
708 setPageComplete(false);
711 private void selectionComplete(final URIish u, final RemoteConfig rc) {
712 setExposedSelection(u, rc);
713 setErrorMessage(null);
714 setPageComplete(true);
715 notifySelectionChanged();
718 private void setExposedSelection(final URIish u, final RemoteConfig rc) {
719 final RepositorySelection newSelection = new RepositorySelection(u, rc);
720 if (newSelection.equals(selection))
721 return;
723 selection = newSelection;
724 notifySelectionChanged();
727 private void updateRemoteAndURIPanels() {
728 setEnabledRecursively(uriPanel, isURISelected());
729 if (uriPanel.getEnabled())
730 updateAuthGroup();
731 if (configuredRemotes != null)
732 setEnabledRecursively(remotePanel, !isURISelected());
735 private void updateAuthGroup() {
736 switch (scheme.getSelectionIndex()) {
737 case S_GIT:
738 hostText.setEnabled(true);
739 portText.setEnabled(true);
740 setEnabledRecursively(authGroup, false);
741 break;
742 case S_SSH:
743 case S_SFTP:
744 case S_HTTP:
745 case S_HTTPS:
746 case S_FTP:
747 hostText.setEnabled(true);
748 portText.setEnabled(true);
749 setEnabledRecursively(authGroup, true);
750 break;
751 case S_FILE:
752 hostText.setEnabled(false);
753 portText.setEnabled(false);
754 setEnabledRecursively(authGroup, false);
755 break;
759 @Override
760 public void setVisible(boolean visible) {
761 super.setVisible(visible);
762 if (visible)
763 uriText.setFocus();
767 * Adds a URI string to the list of previously added ones
769 * TODO move this to some proper preferences handling class instead of
770 * making it static
772 * @param stringToAdd
774 public static void saveUriInPrefs(String stringToAdd) {
776 List<String> uriStrings = getUrisFromPrefs();
778 if (uriStrings.indexOf(stringToAdd) == 0)
779 return;
780 uriStrings.add(0, stringToAdd);
782 IEclipsePreferences prefs = new InstanceScope().getNode(Activator
783 .getPluginId());
785 StringBuilder sb = new StringBuilder();
786 StringBuilder lb = new StringBuilder();
788 // there is no "good" separator for URIish, so we
789 // keep track of the URI lengths separately
790 for (String uriString : uriStrings) {
791 sb.append(uriString);
792 lb.append(uriString.length());
793 lb.append(" "); //$NON-NLS-1$
795 prefs.put(USED_URIS_PREF, sb.toString());
796 prefs.put(USED_URIS_LENGTH_PREF, lb.toString());
798 try {
799 prefs.flush();
800 } catch (BackingStoreException e) {
801 // we simply ignore this here
806 * Gets the previously added URIs from the preferences
808 * TODO move this to some proper preferences handling class instead of
809 * making it static
811 * @return a (possibly empty) list of URIs, never <code>null</code>
813 public static List<String> getUrisFromPrefs() {
815 // use a TreeSet to get the same sorting always
816 List<String> uriStrings = new ArrayList<String>();
818 IEclipsePreferences prefs = new InstanceScope().getNode(Activator
819 .getPluginId());
820 // since there is no "good" separator for URIish, so we
821 // keep track of the URI lengths separately
822 String uriLengths = prefs.get(USED_URIS_LENGTH_PREF, ""); //$NON-NLS-1$
823 String uris = prefs.get(USED_URIS_PREF, ""); //$NON-NLS-1$
825 StringTokenizer tok = new StringTokenizer(uriLengths, " "); //$NON-NLS-1$
826 int offset = 0;
827 while (tok.hasMoreTokens()) {
828 try {
829 int length = Integer.parseInt(tok.nextToken());
830 if (uris.length() >= (offset + length)) {
831 uriStrings.add(uris.substring(offset, offset + length));
832 offset += length;
834 } catch (NumberFormatException nfe) {
835 // ignore here
840 return uriStrings;
843 private void setEnabledRecursively(final Control control,
844 final boolean enable) {
845 control.setEnabled(enable);
846 if (control instanceof Composite)
847 for (final Control child : ((Composite) control).getChildren())
848 setEnabledRecursively(child, enable);
851 private void addContentProposalToUriText(Text uriTextField) {
853 UIUtils.addBulbDecorator(uriTextField, UIText.RepositorySelectionPage_ShowPreviousURIs_HoverText);
855 IContentProposalProvider cp = new IContentProposalProvider() {
857 public IContentProposal[] getProposals(String contents, int position) {
859 List<IContentProposal> resultList = new ArrayList<IContentProposal>();
861 String patternString = contents;
862 while (patternString.length() > 0
863 && patternString.charAt(0) == ' ')
864 patternString = patternString.substring(1);
865 // make the simplest possible pattern check: allow "*"
866 // for multiple characters
867 patternString = patternString.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
868 // make sure we add a (logical) * at the end
869 if (!patternString.endsWith(".*")) { //$NON-NLS-1$
870 patternString = patternString + ".*"; //$NON-NLS-1$
872 // let's compile a case-insensitive pattern (assumes ASCII only)
873 Pattern pattern;
874 try {
875 pattern = Pattern.compile(patternString,
876 Pattern.CASE_INSENSITIVE);
877 } catch (PatternSyntaxException e) {
878 pattern = null;
881 List<String> uriStrings = getUrisFromPrefs();
882 for (final String uriString : uriStrings) {
884 if (pattern != null
885 && !pattern.matcher(uriString).matches())
886 continue;
888 IContentProposal propsal = new IContentProposal() {
890 public String getLabel() {
891 return null;
894 public String getDescription() {
895 return null;
898 public int getCursorPosition() {
899 return 0;
902 public String getContent() {
903 return uriString;
906 resultList.add(propsal);
909 return resultList.toArray(new IContentProposal[resultList
910 .size()]);
914 // set the acceptance style to always replace the complete content
915 new ContentProposalAdapter(uriTextField, new TextContentAdapter(), cp,
916 null, null)
917 .setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);