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