/******************************************************************************* * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.aptana.ide.core.ui.contentassist; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.jface.bindings.TriggerSequence; import org.eclipse.jface.contentassist.AbstractControlContentAssistSubjectAdapter; import org.eclipse.jface.contentassist.ComboContentAssistSubjectAdapter; import org.eclipse.jface.contentassist.SubjectControlContentAssistant; import org.eclipse.jface.contentassist.TextContentAssistSubjectAdapter; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.handlers.IHandlerActivation; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; /** * @author Pavel Petrochenko * */ public final class ContentAssistHandler { /** * The target control. */ private Control fControl; /** * The content assist subject adapter. */ private AbstractControlContentAssistSubjectAdapter fContentAssistSubjectAdapter; /** * The content assistant. */ private SubjectControlContentAssistant fContentAssistant; /** * The currently installed FocusListener, or <code>null</code> iff none installed. This is also used as flag to * tell whether content assist is enabled */ private FocusListener fFocusListener; /** * The currently installed IHandlerActivation, or <code>null</code> iff none installed. */ private IHandlerActivation fHandlerActivation; /** * Creates a new {@link ContentAssistHandler} for the given {@link Combo}. Only a single * {@link ContentAssistHandler} may be installed on a {@link Combo} instance. Content Assist is enabled by default. * * @param combo * target combo * @param contentAssistant * a configured content assistant * @return a new {@link ContentAssistHandler} */ public static ContentAssistHandler createHandlerForCombo(Combo combo, SubjectControlContentAssistant contentAssistant) { return new ContentAssistHandler(combo, new ComboContentAssistSubjectAdapter(combo), contentAssistant); } /** * Creates a new {@link ContentAssistHandler} for the given {@link Text}. Only a single * {@link ContentAssistHandler} may be installed on a {@link Text} instance. Content Assist is enabled by default. * * @param text * target text * @param contentAssistant * a configured content assistant * @return a new {@link ContentAssistHandler} */ public static ContentAssistHandler createHandlerForText(Text text, SubjectControlContentAssistant contentAssistant) { return new ContentAssistHandler(text, new TextContentAssistSubjectAdapter(text), contentAssistant); } /** * Internal constructor. * * @param control * target control * @param subjectAdapter * content assist subject adapter * @param contentAssistant * content assistant */ private ContentAssistHandler(Control control, AbstractControlContentAssistSubjectAdapter subjectAdapter, SubjectControlContentAssistant contentAssistant) { this.fControl = control; this.fContentAssistant = contentAssistant; this.fContentAssistSubjectAdapter = subjectAdapter; this.setEnabled(true); this.fControl.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { ContentAssistHandler.this.setEnabled(false); } }); } /** * @return <code>true</code> iff content assist is enabled */ public boolean isEnabled() { return this.fFocusListener != null; } /** * Controls enablement of content assist. When enabled, a cue is shown next to the focused field and the affordance * hover shows the shortcut. * * @param enable * enable content assist iff true */ public void setEnabled(boolean enable) { if (enable == this.isEnabled()) { return; } if (enable) { this.enable(); } else { this.disable(); } } /** * Enable content assist. */ private void enable() { if (!this.fControl.isDisposed()) { this.fContentAssistant.install(this.fContentAssistSubjectAdapter); this.installCueLabelProvider(); this.installFocusListener(); if (this.fControl.isFocusControl()) { this.activateHandler(); } } } /** * Disable content assist. */ private void disable() { if (!this.fControl.isDisposed()) { this.fContentAssistant.uninstall(); this.fContentAssistSubjectAdapter.setContentAssistCueProvider(null); this.fControl.removeFocusListener(this.fFocusListener); this.fFocusListener = null; if (this.fHandlerActivation != null) { this.deactivateHandler(); } } } /** * Create and install the {@link LabelProvider} for fContentAssistSubjectAdapter. */ private void installCueLabelProvider() { ILabelProvider labelProvider = new LabelProvider() { /* * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object) */ public String getText(Object element) { IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench().getAdapter( IBindingService.class); TriggerSequence[] activeBindings = bindingService .getActiveBindingsFor(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); if (activeBindings.length == 0) { return Messages.ContentAssistHandler_TXT_CA_Available; } return activeBindings[0].format(); } }; this.fContentAssistSubjectAdapter.setContentAssistCueProvider(labelProvider); } /** * Create fFocusListener and install it on fControl. */ private void installFocusListener() { this.fFocusListener = new FocusListener() { public void focusGained(final FocusEvent e) { if (ContentAssistHandler.this.fHandlerActivation == null) { ContentAssistHandler.this.activateHandler(); } } public void focusLost(FocusEvent e) { if (ContentAssistHandler.this.fHandlerActivation != null) { ContentAssistHandler.this.deactivateHandler(); } } }; this.fControl.addFocusListener(this.fFocusListener); } /** * Create and register fHandlerSubmission. */ private void activateHandler() { IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench().getAdapter(IHandlerService.class); if (handlerService == null) { return; } IHandler handler = new AbstractHandler() { public Object execute(ExecutionEvent event) throws ExecutionException { if (ContentAssistHandler.this.isEnabled()) { ContentAssistHandler.this.fContentAssistant.showPossibleCompletions(); } return null; } }; this.fHandlerActivation = handlerService.activateHandler( ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, handler); } /** * Unregister the {@link IHandlerActivation} from the shell. */ private void deactivateHandler() { IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench().getAdapter(IHandlerService.class); if (handlerService != null) { handlerService.deactivateHandler(this.fHandlerActivation); } this.fHandlerActivation = null; } }