/* * Verify that the POM XML editor is smart enough to offer proper content assist even if the POM does not explicitly * declare a schema (MNGECLIPSE-1770). */ @Test public void testContentAssistWithoutSchema() throws Exception { String name = PROJECT_NAME + "/ca.pom"; String str = "<project>\n" // + "<modelVersion>4.0.0</modelVersion>\n" // + "<groupId>test</groupId>\n" // + "<artifactId>ca</artifactId>\n" // + "<packaging>jar</packaging>\n" // + "<version>0.0.1-SNAPSHOT</version>\n" // + "<build>\n" // + "</build>\n" // + "</project>\n"; createFile(name, str); openPomFile(name); selectEditorTab(TAB_POM_XML); findText("</build>"); SWTBotEclipseEditor editor = bot.activeEditor().toTextEditor(); editor.pressShortcut(KeyStroke.getInstance(SWT.ARROW_LEFT)); editor.pressShortcut(SWT.CTRL, ' '); editor.pressShortcut(KeyStroke.getInstance(SWT.LF)); String text = editor.getText(); assertTrue(text, text.contains("<defaultGoal>")); }
@Override protected void doExecuteRefactoring() { bot.selectElementToRefactor(getTestFileFullName(), 24, 6, "Child".length()); bot.invokeRefactoringFromMenu("Use Supertype Where Possible..."); bot.activateShellWithName("Use Super Type Where Possible"); bot.getCurrentTree().pressShortcut(org.eclipse.jface.bindings.keys.KeyStroke.getInstance('G')); bot.clickButtons(IDialogConstants.OK_LABEL); }
@Test public void testKeyStrokes() { final KeyStroke lKeyStroke = KeyStroke.getInstance(SWT.MOD1, 'I'); assertEquals(SWT.MOD1 | 'I', lKeyStroke.getModifierKeys() | lKeyStroke.getNaturalKey()); assertEquals("CTRL+I", lKeyStroke.format()); final KeySequence lSequence = KeySequence.getInstance(lKeyStroke); assertEquals("CTRL+I", lSequence.format()); assertEquals(SWT.MOD1 | 'I', getKeyCode(lSequence)); }
public static ContentProposalAdapter createContentProposal( final Text text, String[] proposedValues) { SimpleContentProposalProvider proposalProvider = new SimpleContentProposalProvider(proposedValues); proposalProvider.setFiltering(true); KeyStroke keyStroke = KeyStroke.getInstance(SWT.CONTROL, ' '); ContentProposalAdapter proposalAdapter = new ContentProposalAdapter( text, new TextContentAdapter(), proposalProvider, keyStroke, null); proposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); return proposalAdapter; }
/** * Creates an {@link SourceViewer} and returns the {@link StyledText} widget of the viewer as the * cell editors control. Some code is copied from {@link XtextEditor}. */ @Override protected Control createControl(Composite parent) { StyledText styledText = (StyledText) super.createControl(parent); styledText.addFocusListener( new FocusAdapter() { public void focusLost(FocusEvent e) { XtextStyledTextCellEditor.this.focusLost(); } }); // adapt to xtext xtextAdapter = new StyledTextXtextAdapter( injector, contextFakeResourceProvider == null ? IXtextFakeContextResourcesProvider.NULL_CONTEXT_PROVIDER : contextFakeResourceProvider, project); xtextAdapter.adapt(styledText); if (provider != null) { xtextAdapter .getFakeResourceContext() .getFakeResource() .eAdapters() .add(new ContextElementAdapter(provider)); } // configure content assist final IContentAssistant contentAssistant = xtextAdapter.getContentAssistant(); completionProposalAdapter = new CompletionProposalAdapter( styledText, contentAssistant, KeyStroke.getInstance(SWT.CTRL, SWT.SPACE), null); // This listener notifies the modification, when text is selected via // proposal. A ModifyEvent is not thrown by the StyledText in this case. xtextAdapter .getXtextSourceviewer() .addTextListener( new ITextListener() { public void textChanged(TextEvent event) { editOccured(null); } }); if ((styledText.getStyle() & SWT.SINGLE) != 0) { // The regular key down event is too late (after popup is closed // again). // when using the StyledText.VerifyKey event (3005), we get the // event early enough! styledText.addListener( 3005, new Listener() { public void handleEvent(Event event) { if (event.character == SWT.CR && !completionProposalAdapter.isProposalPopupOpen()) { focusLost(); } } }); } styledText.addListener( 3005, new Listener() { public void handleEvent(Event event) { if (event.character == '\u001b' // ESC && !completionProposalAdapter.isProposalPopupOpen()) { XtextStyledTextCellEditor.this.fireCancelEditor(); } } }); initContextMenu(styledText); return styledText; }
/** Some utilities for UI code */ public class UIUtils { /** these activate the content assist; alphanumeric, space plus some expected special chars */ private static final char[] VALUE_HELP_ACTIVATIONCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123457890*@ <>" .toCharArray(); //$NON-NLS-1$ /** A keystroke for a "submit" action, see {@link #isSubmitKeyEvent(KeyEvent)} */ public static final KeyStroke SUBMIT_KEY_STROKE = KeyStroke.getInstance(SWT.MOD1, SWT.CR); /** * Handles a "previously used values" content assist. * * <p>Adding this to a text field will enable "content assist" by keeping track of the previously * used valued for this field. The previously used values will be shown in the order they were * last used (most recently used ones coming first in the list) and the number of entries is * limited. * * <p>A "bulb" decorator will indicate that content assist is available for the field, and a tool * tip is provided giving more information. * * <p>Content assist is activated by either typing in the field or by using a dedicated key stroke * which is indicated in the tool tip. The list will be filtered with the content already in the * text field with '*' being usable as wild card. * * <p>Note that the application must issue a call to {@link #updateProposals()} in order to add a * new value to the "previously used values" list. * * <p>The list will be persisted in the plug-in dialog settings. * * @noextend not to be extended by clients * @noimplement not to be implemented by clients, use {@link * UIUtils#addPreviousValuesContentProposalToText(Text, String)} to create instances of this */ public interface IPreviousValueProposalHandler { /** * Updates the proposal list from the value in the text field. * * <p>The value will be truncated to the first 2000 characters in order to limit data size. * * <p>Note that this must be called in the UI thread, since it accesses the text field. * * <p>If the value is already in the list, it will become the first entry, otherwise it will be * added at the beginning. Note that empty Strings will not be stored. The length of the list is * limited, and the "oldest" entries will be removed once the limit is exceeded. * * <p>This call should only be issued if the value in the text field is "valid" in terms of the * application. */ public void updateProposals(); } /** Used for {@link UIUtils#addRefContentProposalToText(Text, Repository, IRefListProvider)} */ public interface IRefListProvider { /** @return the List of {@link Ref}s to propose */ public List<Ref> getRefList(); } /** * @param id see {@link FontRegistry#get(String)} * @return the font */ public static Font getFont(final String id) { return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getFontRegistry().get(id); } /** * @param id see {@link FontRegistry#getBold(String)} * @return the font */ public static Font getBoldFont(final String id) { return PlatformUI.getWorkbench() .getThemeManager() .getCurrentTheme() .getFontRegistry() .getBold(id); } /** * @param id see {@link FontRegistry#getItalic(String)} * @return the font */ public static Font getItalicFont(final String id) { return PlatformUI.getWorkbench() .getThemeManager() .getCurrentTheme() .getFontRegistry() .getItalic(id); } /** * Adds little bulb decoration to given control. Bulb will appear in top left corner of control * after giving focus for this control. * * <p>After clicking on bulb image text from <code>tooltip</code> will appear. * * @param control instance of {@link Control} object with should be decorated * @param tooltip text value which should appear after clicking on bulb image. */ public static void addBulbDecorator(final Control control, final String tooltip) { ControlDecoration dec = new ControlDecoration(control, SWT.TOP | SWT.LEFT); dec.setImage( FieldDecorationRegistry.getDefault() .getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL) .getImage()); dec.setShowOnlyOnFocus(true); dec.setShowHover(true); dec.setDescriptionText(tooltip); } /** * Adds a "previously used values" content proposal handler to a text field. * * <p>The keyboard shortcut will be "M1+SPACE" and the list will be limited to 10 values. * * @param textField the text field * @param preferenceKey the key under which to store the "previously used values" in the dialog * settings * @return the handler the proposal handler */ public static IPreviousValueProposalHandler addPreviousValuesContentProposalToText( final Text textField, final String preferenceKey) { KeyStroke stroke; try { stroke = KeyStroke.getInstance("M1+SPACE"); // $NON-NLS-1$ addBulbDecorator(textField, NLS.bind(UIText.UIUtils_PressShortcutMessage, stroke.format())); } catch (ParseException e1) { Activator.handleError(e1.getMessage(), e1, false); stroke = null; addBulbDecorator(textField, UIText.UIUtils_StartTypingForPreviousValuesMessage); } IContentProposalProvider cp = new IContentProposalProvider() { public IContentProposal[] getProposals(String contents, int position) { List<IContentProposal> resultList = new ArrayList<IContentProposal>(); // make the simplest possible pattern check: allow "*" // for multiple characters String patternString = contents; // ignore spaces in the beginning while (patternString.length() > 0 && patternString.charAt(0) == ' ') { patternString = patternString.substring(1); } // we quote the string as it may contain spaces // and other stuff colliding with the Pattern patternString = Pattern.quote(patternString); patternString = patternString.replaceAll("\\x2A", ".*"); // $NON-NLS-1$ //$NON-NLS-2$ // make sure we add a (logical) * at the end if (!patternString.endsWith(".*")) { // $NON-NLS-1$ patternString = patternString + ".*"; // $NON-NLS-1$ } // let's compile a case-insensitive pattern (assumes ASCII only) Pattern pattern; try { pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); } catch (PatternSyntaxException e) { pattern = null; } String[] proposals = org.eclipse.egit.ui.Activator.getDefault() .getDialogSettings() .getArray(preferenceKey); if (proposals != null) for (final String uriString : proposals) { if (pattern != null && !pattern.matcher(uriString).matches()) continue; IContentProposal propsal = new IContentProposal() { public String getLabel() { return null; } public String getDescription() { return null; } public int getCursorPosition() { return 0; } public String getContent() { return uriString; } }; resultList.add(propsal); } return resultList.toArray(new IContentProposal[resultList.size()]); } }; ContentProposalAdapter adapter = new ContentProposalAdapter( textField, new TextContentAdapter(), cp, stroke, VALUE_HELP_ACTIVATIONCHARS); // set the acceptance style to always replace the complete content adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); return new IPreviousValueProposalHandler() { public void updateProposals() { String value = textField.getText(); // don't store empty values if (value.length() > 0) { // we don't want to save too much in the preferences if (value.length() > 2000) { value = value.substring(0, 1999); } // now we need to mix the value into the list IDialogSettings settings = org.eclipse.egit.ui.Activator.getDefault().getDialogSettings(); String[] existingValues = settings.getArray(preferenceKey); if (existingValues == null) { existingValues = new String[] {value}; settings.put(preferenceKey, existingValues); } else { List<String> values = new ArrayList<String>(existingValues.length + 1); for (String existingValue : existingValues) values.add(existingValue); // if it is already the first value, we don't need to do // anything if (values.indexOf(value) == 0) return; values.remove(value); // we insert at the top values.add(0, value); // make sure to not store more than the maximum number // of values while (values.size() > 10) values.remove(values.size() - 1); settings.put(preferenceKey, values.toArray(new String[values.size()])); } } } }; } /** * Adds a content proposal for {@link Ref}s (branches, tags...) to a text field * * @param textField the text field * @param repository the repository * @param refListProvider provides the {@link Ref}s to show in the proposal */ public static final void addRefContentProposalToText( final Text textField, final Repository repository, final IRefListProvider refListProvider) { KeyStroke stroke; try { stroke = KeyStroke.getInstance("M1+SPACE"); // $NON-NLS-1$ UIUtils.addBulbDecorator( textField, NLS.bind(UIText.UIUtils_PressShortcutMessage, stroke.format())); } catch (ParseException e1) { Activator.handleError(e1.getMessage(), e1, false); stroke = null; UIUtils.addBulbDecorator(textField, UIText.UIUtils_StartTypingForPreviousValuesMessage); } IContentProposalProvider cp = new IContentProposalProvider() { public IContentProposal[] getProposals(String contents, int position) { List<IContentProposal> resultList = new ArrayList<IContentProposal>(); // make the simplest possible pattern check: allow "*" // for multiple characters String patternString = contents; // ignore spaces in the beginning while (patternString.length() > 0 && patternString.charAt(0) == ' ') { patternString = patternString.substring(1); } // we quote the string as it may contain spaces // and other stuff colliding with the Pattern patternString = Pattern.quote(patternString); patternString = patternString.replaceAll("\\x2A", ".*"); // $NON-NLS-1$ //$NON-NLS-2$ // make sure we add a (logical) * at the end if (!patternString.endsWith(".*")) { // $NON-NLS-1$ patternString = patternString + ".*"; // $NON-NLS-1$ } // let's compile a case-insensitive pattern (assumes ASCII only) Pattern pattern; try { pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); } catch (PatternSyntaxException e) { pattern = null; } List<Ref> proposals = refListProvider.getRefList(); if (proposals != null) for (final Ref ref : proposals) { final String shortenedName = Repository.shortenRefName(ref.getName()); if (pattern != null && !pattern.matcher(ref.getName()).matches() && !pattern.matcher(shortenedName).matches()) continue; IContentProposal propsal = new RefContentProposal(repository, ref); resultList.add(propsal); } return resultList.toArray(new IContentProposal[resultList.size()]); } }; ContentProposalAdapter adapter = new ContentProposalAdapter( textField, new TextContentAdapter(), cp, stroke, UIUtils.VALUE_HELP_ACTIVATIONCHARS); // set the acceptance style to always replace the complete content adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); } /** * Set enabled state of the control and all its children * * @param control * @param enable */ public static void setEnabledRecursively(final Control control, final boolean enable) { control.setEnabled(enable); if (control instanceof Composite) for (final Control child : ((Composite) control).getChildren()) setEnabledRecursively(child, enable); } /** * Dispose of the resource when the widget is disposed * * @param widget * @param resource */ public static void hookDisposal(Widget widget, final Resource resource) { if (widget == null || resource == null) return; widget.addDisposeListener( new DisposeListener() { public void widgetDisposed(DisposeEvent e) { resource.dispose(); } }); } /** * Dispose of the resource manager when the widget is disposed * * @param widget * @param resources */ public static void hookDisposal(Widget widget, final ResourceManager resources) { if (widget == null || resources == null) return; widget.addDisposeListener( new DisposeListener() { public void widgetDisposed(DisposeEvent e) { resources.dispose(); } }); } /** * Get editor image for path * * @param path * @return image descriptor */ public static ImageDescriptor getEditorImage(final String path) { if (path != null && path.length() > 0) { final String name = new Path(path).lastSegment(); if (name != null) return PlatformUI.getWorkbench().getEditorRegistry().getImageDescriptor(name); } return PlatformUI.getWorkbench() .getSharedImages() .getImageDescriptor(ISharedImages.IMG_OBJ_FILE); } /** * Get size of image descriptor as point. * * @param descriptor * @return size */ public static Point getSize(ImageDescriptor descriptor) { ImageData data = descriptor.getImageData(); if (data == null) return new Point(0, 0); return new Point(data.width, data.height); } /** * Add expand all and collapse all toolbar items to the given toolbar bound to the given tree * viewer * * @param toolbar * @param viewer * @return given toolbar */ public static ToolBar addExpansionItems(final ToolBar toolbar, final AbstractTreeViewer viewer) { ToolItem collapseItem = new ToolItem(toolbar, SWT.PUSH); Image collapseImage = UIIcons.COLLAPSEALL.createImage(); UIUtils.hookDisposal(collapseItem, collapseImage); collapseItem.setImage(collapseImage); collapseItem.setToolTipText(UIText.UIUtils_CollapseAll); collapseItem.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { viewer.collapseAll(); } }); ToolItem expandItem = new ToolItem(toolbar, SWT.PUSH); Image expandImage = UIIcons.EXPAND_ALL.createImage(); UIUtils.hookDisposal(expandItem, expandImage); expandItem.setImage(expandImage); expandItem.setToolTipText(UIText.UIUtils_ExpandAll); expandItem.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { viewer.expandAll(); } }); return toolbar; } /** * Get dialog bound settings for given class using standard section name * * @param clazz * @return dialog setting */ public static IDialogSettings getDialogBoundSettings(final Class<?> clazz) { return getDialogSettings(clazz.getName() + ".dialogBounds"); // $NON-NLS-1$ } /** * Get dialog settings for given section name * * @param sectionName * @return dialog settings */ public static IDialogSettings getDialogSettings(final String sectionName) { IDialogSettings settings = Activator.getDefault().getDialogSettings(); IDialogSettings section = settings.getSection(sectionName); if (section == null) section = settings.addNewSection(sectionName); return section; } /** * @return The default repository directory as configured in the preferences, with variables * substituted. An empty string if there was an error during substitution. */ public static String getDefaultRepositoryDir() { String dir = Activator.getDefault().getPreferenceStore().getString(UIPreferences.DEFAULT_REPO_DIR); IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager(); try { return manager.performStringSubstitution(dir); } catch (CoreException e) { return ""; //$NON-NLS-1$ } } /** * Is viewer in a usable state? * * @param viewer * @return true if usable, false if null or underlying control is null or disposed */ public static boolean isUsable(final Viewer viewer) { return viewer != null && isUsable(viewer.getControl()); } /** * Is control usable? * * @param control * @return true if usable, false if null or disposed */ public static boolean isUsable(final Control control) { return control != null && !control.isDisposed(); } /** * Run command with specified id * * @param service * @param id */ public static void executeCommand(IHandlerService service, String id) { executeCommand(service, id, null); } /** * Run command with specified id * * @param service * @param id * @param event */ public static void executeCommand(IHandlerService service, String id, Event event) { try { service.executeCommand(id, event); } catch (ExecutionException e) { Activator.handleError(e.getMessage(), e, false); } catch (NotDefinedException e) { Activator.handleError(e.getMessage(), e, false); } catch (NotEnabledException e) { Activator.handleError(e.getMessage(), e, false); } catch (NotHandledException e) { Activator.handleError(e.getMessage(), e, false); } } /** * Determine if the key event represents a "submit" action (<modifier>+Enter). * * @param event * @return true, if it means submit, false otherwise */ public static boolean isSubmitKeyEvent(KeyEvent event) { return (event.stateMask & SWT.MODIFIER_MASK) != 0 && event.keyCode == SUBMIT_KEY_STROKE.getNaturalKey(); } /** * Prompt for saving all dirty editors for resources in the working directory of the specified * repository. * * @param repository * @return true, if the user opted to continue, false otherwise * @see IWorkbench#saveAllEditors(boolean) */ public static boolean saveAllEditors(Repository repository) { IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); return workbench.saveAll(window, window, new RepositorySaveableFilter(repository), true); } /** * @param workbenchWindow the workbench window to use for creating the show in menu. * @return the show in menu */ public static MenuManager createShowInMenu(IWorkbenchWindow workbenchWindow) { MenuManager showInSubMenu = new MenuManager(getShowInMenuLabel()); showInSubMenu.add(ContributionItemFactory.VIEWS_SHOW_IN.create(workbenchWindow)); return showInSubMenu; } /** * Use hyperlink detectors to find a text viewer's hyperlinks and return the style ranges to * render them. * * @param textViewer * @param hyperlinkDetectors * @return the style ranges to render the detected hyperlinks */ public static StyleRange[] getHyperlinkDetectorStyleRanges( ITextViewer textViewer, IHyperlinkDetector[] hyperlinkDetectors) { List<StyleRange> styleRangeList = new ArrayList<StyleRange>(); if (hyperlinkDetectors != null && hyperlinkDetectors.length > 0) { for (int i = 0; i < textViewer.getTextWidget().getText().length(); i++) { IRegion region = new Region(i, 0); for (IHyperlinkDetector hyperLinkDetector : hyperlinkDetectors) { IHyperlink[] hyperlinks = hyperLinkDetector.detectHyperlinks(textViewer, region, true); if (hyperlinks != null) { for (IHyperlink hyperlink : hyperlinks) { StyleRange hyperlinkStyleRange = new StyleRange( hyperlink.getHyperlinkRegion().getOffset(), hyperlink.getHyperlinkRegion().getLength(), Display.getDefault().getSystemColor(SWT.COLOR_BLUE), Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); hyperlinkStyleRange.underline = true; styleRangeList.add(hyperlinkStyleRange); } } } } } StyleRange[] styleRangeArray = new StyleRange[styleRangeList.size()]; styleRangeList.toArray(styleRangeArray); return styleRangeArray; } private static String getShowInMenuLabel() { IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class); if (bindingService != null) { String keyBinding = bindingService.getBestActiveBindingFormattedFor( IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_QUICK_MENU); if (keyBinding != null) return UIText.UIUtils_ShowInMenuLabel + '\t' + keyBinding; } return UIText.UIUtils_ShowInMenuLabel; } }
/** * Adds a content proposal for {@link Ref}s (branches, tags...) to a text field * * @param textField the text field * @param repository the repository * @param refListProvider provides the {@link Ref}s to show in the proposal */ public static final void addRefContentProposalToText( final Text textField, final Repository repository, final IRefListProvider refListProvider) { KeyStroke stroke; try { stroke = KeyStroke.getInstance("M1+SPACE"); // $NON-NLS-1$ UIUtils.addBulbDecorator( textField, NLS.bind(UIText.UIUtils_PressShortcutMessage, stroke.format())); } catch (ParseException e1) { Activator.handleError(e1.getMessage(), e1, false); stroke = null; UIUtils.addBulbDecorator(textField, UIText.UIUtils_StartTypingForPreviousValuesMessage); } IContentProposalProvider cp = new IContentProposalProvider() { public IContentProposal[] getProposals(String contents, int position) { List<IContentProposal> resultList = new ArrayList<IContentProposal>(); // make the simplest possible pattern check: allow "*" // for multiple characters String patternString = contents; // ignore spaces in the beginning while (patternString.length() > 0 && patternString.charAt(0) == ' ') { patternString = patternString.substring(1); } // we quote the string as it may contain spaces // and other stuff colliding with the Pattern patternString = Pattern.quote(patternString); patternString = patternString.replaceAll("\\x2A", ".*"); // $NON-NLS-1$ //$NON-NLS-2$ // make sure we add a (logical) * at the end if (!patternString.endsWith(".*")) { // $NON-NLS-1$ patternString = patternString + ".*"; // $NON-NLS-1$ } // let's compile a case-insensitive pattern (assumes ASCII only) Pattern pattern; try { pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); } catch (PatternSyntaxException e) { pattern = null; } List<Ref> proposals = refListProvider.getRefList(); if (proposals != null) for (final Ref ref : proposals) { final String shortenedName = Repository.shortenRefName(ref.getName()); if (pattern != null && !pattern.matcher(ref.getName()).matches() && !pattern.matcher(shortenedName).matches()) continue; IContentProposal propsal = new RefContentProposal(repository, ref); resultList.add(propsal); } return resultList.toArray(new IContentProposal[resultList.size()]); } }; ContentProposalAdapter adapter = new ContentProposalAdapter( textField, new TextContentAdapter(), cp, stroke, UIUtils.VALUE_HELP_ACTIVATIONCHARS); // set the acceptance style to always replace the complete content adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); }
/** * Adds a "previously used values" content proposal handler to a text field. * * <p>The keyboard shortcut will be "M1+SPACE" and the list will be limited to 10 values. * * @param textField the text field * @param preferenceKey the key under which to store the "previously used values" in the dialog * settings * @return the handler the proposal handler */ public static IPreviousValueProposalHandler addPreviousValuesContentProposalToText( final Text textField, final String preferenceKey) { KeyStroke stroke; try { stroke = KeyStroke.getInstance("M1+SPACE"); // $NON-NLS-1$ addBulbDecorator(textField, NLS.bind(UIText.UIUtils_PressShortcutMessage, stroke.format())); } catch (ParseException e1) { Activator.handleError(e1.getMessage(), e1, false); stroke = null; addBulbDecorator(textField, UIText.UIUtils_StartTypingForPreviousValuesMessage); } IContentProposalProvider cp = new IContentProposalProvider() { public IContentProposal[] getProposals(String contents, int position) { List<IContentProposal> resultList = new ArrayList<IContentProposal>(); // make the simplest possible pattern check: allow "*" // for multiple characters String patternString = contents; // ignore spaces in the beginning while (patternString.length() > 0 && patternString.charAt(0) == ' ') { patternString = patternString.substring(1); } // we quote the string as it may contain spaces // and other stuff colliding with the Pattern patternString = Pattern.quote(patternString); patternString = patternString.replaceAll("\\x2A", ".*"); // $NON-NLS-1$ //$NON-NLS-2$ // make sure we add a (logical) * at the end if (!patternString.endsWith(".*")) { // $NON-NLS-1$ patternString = patternString + ".*"; // $NON-NLS-1$ } // let's compile a case-insensitive pattern (assumes ASCII only) Pattern pattern; try { pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); } catch (PatternSyntaxException e) { pattern = null; } String[] proposals = org.eclipse.egit.ui.Activator.getDefault() .getDialogSettings() .getArray(preferenceKey); if (proposals != null) for (final String uriString : proposals) { if (pattern != null && !pattern.matcher(uriString).matches()) continue; IContentProposal propsal = new IContentProposal() { public String getLabel() { return null; } public String getDescription() { return null; } public int getCursorPosition() { return 0; } public String getContent() { return uriString; } }; resultList.add(propsal); } return resultList.toArray(new IContentProposal[resultList.size()]); } }; ContentProposalAdapter adapter = new ContentProposalAdapter( textField, new TextContentAdapter(), cp, stroke, VALUE_HELP_ACTIVATIONCHARS); // set the acceptance style to always replace the complete content adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); return new IPreviousValueProposalHandler() { public void updateProposals() { String value = textField.getText(); // don't store empty values if (value.length() > 0) { // we don't want to save too much in the preferences if (value.length() > 2000) { value = value.substring(0, 1999); } // now we need to mix the value into the list IDialogSettings settings = org.eclipse.egit.ui.Activator.getDefault().getDialogSettings(); String[] existingValues = settings.getArray(preferenceKey); if (existingValues == null) { existingValues = new String[] {value}; settings.put(preferenceKey, existingValues); } else { List<String> values = new ArrayList<String>(existingValues.length + 1); for (String existingValue : existingValues) values.add(existingValue); // if it is already the first value, we don't need to do // anything if (values.indexOf(value) == 0) return; values.remove(value); // we insert at the top values.add(0, value); // make sure to not store more than the maximum number // of values while (values.size() > 10) values.remove(values.size() - 1); settings.put(preferenceKey, values.toArray(new String[values.size()])); } } } }; }
private void addRefContentProposalToText(final Text textField) { KeyStroke stroke; try { stroke = KeyStroke.getInstance("CTRL+SPACE"); // $NON-NLS-1$ UIUtils.addBulbDecorator( textField, NLS.bind(UIText.FetchGerritChangePage_ContentAssistTooltip, stroke.format())); } catch (ParseException e1) { Activator.handleError(e1.getMessage(), e1, false); stroke = null; } IContentProposalProvider cp = new IContentProposalProvider() { public IContentProposal[] getProposals(String contents, int position) { List<IContentProposal> resultList = new ArrayList<IContentProposal>(); // make the simplest possible pattern check: allow "*" // for multiple characters String patternString = contents; // ignore spaces in the beginning while (patternString.length() > 0 && patternString.charAt(0) == ' ') patternString = patternString.substring(1); // we quote the string as it may contain spaces // and other stuff colliding with the Pattern patternString = Pattern.quote(patternString); patternString = patternString.replaceAll("\\x2A", ".*"); // $NON-NLS-1$ //$NON-NLS-2$ // make sure we add a (logical) * at the end if (!patternString.endsWith(".*")) // $NON-NLS-1$ patternString = patternString + ".*"; // $NON-NLS-1$ // let's compile a case-insensitive pattern (assumes ASCII only) Pattern pattern; try { pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); } catch (PatternSyntaxException e) { pattern = null; } List<Change> proposals; try { proposals = getRefsForContentAssist(); } catch (InvocationTargetException e) { Activator.handleError(e.getMessage(), e, false); return null; } catch (InterruptedException e) { return null; } if (proposals != null) for (final Change ref : proposals) { if (pattern != null && !pattern.matcher(ref.getChangeNumber().toString()).matches()) continue; IContentProposal propsal = new ChangeContentProposal(ref); resultList.add(propsal); } return resultList.toArray(new IContentProposal[resultList.size()]); } }; ContentProposalAdapter adapter = new ContentProposalAdapter(textField, new TextContentAdapter(), cp, stroke, null); // set the acceptance style to always replace the complete content adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); }