/*******************************************************************************
* Copyright (c) 2007 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.model.ui.attribute;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.fieldassist.ComboContentAdapter;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalListener2;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.pde.internal.ui.editor.contentassist.TypeContentProposal;
import org.eclipse.swt.SWT;
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.graphics.Image;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.jboss.tools.common.meta.XAttribute;
import org.jboss.tools.common.meta.action.XEntityData;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.ui.ModelUIPlugin;
import org.jboss.tools.common.model.ui.attribute.adapter.DefaultValueAdapter;
/**
* @author Viacheslav Kabanovich
*/
public class AttributeContentProposalProviderFactory {
private static List<IAttributeContentProposalProvider> EMPTY = new ArrayList<IAttributeContentProposalProvider>();
public static KeyStroke getCtrlSpaceKeyStroke() {
KeyStroke ks = null;
try {
ks = KeyStroke.getInstance("Ctrl+Space"); //$NON-NLS-1$
} catch (ParseException e) {
//Cannot happen, this code is safe.
ModelUIPlugin.getPluginLog().logError(e);
}
return ks;
}
public static void registerContentAssist(DefaultValueAdapter valueAdapter, Control control) {
registerContentAssist(valueAdapter, control, null);
}
public static void registerContentAssist(DefaultValueAdapter valueAdapter, Control control, IContentProposalListener2 listener) {
XModelObject object = valueAdapter.getModelObject();
XEntityData data = null;
if(valueAdapter.getAttributeData() != null) {
data = valueAdapter.getAttributeData().getEntityData();
}
XAttribute attr = valueAdapter.getAttribute();
if (attr == null && valueAdapter.getAttributeData() != null) {
attr = valueAdapter.getAttributeData().getAttribute();
}
registerContentAssist(object, data, attr, control, listener);
}
public static void registerContentAssist(XModelObject object, XEntityData data, XAttribute attr, Control control) {
registerContentAssist(object, data, attr, control, null);
}
public static void registerContentAssist(XModelObject object, XEntityData data, XAttribute attr, final Control control, IContentProposalListener2 listener) {
IControlContentAdapter controlAdapter = control instanceof Text
? new TextContentAdapter()
: control instanceof Combo
? new ComboContentAdapter()
: null;
if(controlAdapter == null) {
return;
}
AttributeContentProposalProviderFactory factory = new AttributeContentProposalProviderFactory();
final List<IAttributeContentProposalProvider> ps = factory
.getContentProposalProviders(object, attr);
boolean added = false;
for (IAttributeContentProposalProvider p : ps) {
p.init(object, data, attr);
IContentProposalProvider cpp = p.getContentProposalProvider();
if (cpp == null)
continue;
ContentProposalAdapter adapter = new ContentProposalAdapter(
control,
controlAdapter,
cpp,
AttributeContentProposalProviderFactory.getCtrlSpaceKeyStroke(),
null);
//TODO let IAttributeContentProposalProvider return specific label provider.
adapter.setLabelProvider(new LabelProvider() {
public Image getImage(Object element) {
if(element instanceof TypeContentProposal) {
return ((TypeContentProposal)element).getImage();
}
return null;
}
@Override
public String getText(Object element) {
if (element instanceof IContentProposal) {
IContentProposal proposal = (IContentProposal) element;
return proposal.getLabel() == null ? proposal.getContent()
: proposal.getLabel();
}
return super.getText(element);
}
});
adapter.setPropagateKeys(true);
adapter.setProposalAcceptanceStyle(p.getProposalAcceptanceStyle());
if(listener != null) {
adapter.addContentProposalListener(listener);
}
added = true;
}
if (!ps.isEmpty()) {
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
for (IAttributeContentProposalProvider p : ps) {
p.dispose();
}
}
});
}
if(added) {
FocusListener focusListener = new FocusListener() {
ControlDecoration controlDecoration;
@Override
public void focusLost(FocusEvent e) {
control.removeFocusListener(this);
if(controlDecoration != null) {
controlDecoration.setShowOnlyOnFocus(true);
}
}
@Override
public void focusGained(FocusEvent e) {
if(controlDecoration == null) {
controlDecoration = addControlDecoration(control, ps);
}
}
};
control.addFocusListener(focusListener);
}
}
private static ControlDecoration addControlDecoration(Control control, final List<IAttributeContentProposalProvider> ps) {
int bits = SWT.TOP | SWT.LEFT;
ControlDecoration controlDecoration = new ControlDecoration(control, bits) {
public Image getImage() {
for (IAttributeContentProposalProvider p : ps) {
LabelProvider lp = p.getCustomLabelProbider();
if(lp != null) {
Image image = lp.getImage(getControl());
if(image != null) return image;
}
}
return super.getImage();
}
};
// Configure text widget decoration
// No margin
controlDecoration.setMarginWidth(0);
// Custom hover tip text
controlDecoration.setDescriptionText("code assist" /*PDEUIMessages.PDEJavaHelper_msgContentAssistAvailable*/);
// Custom hover properties
controlDecoration.setShowHover(true);
// Hover image to use
FieldDecoration contentProposalImage = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
controlDecoration.setImage(contentProposalImage.getImage());
return controlDecoration;
}
static String POINT_ID = ModelUIPlugin.PLUGIN_ID + ".attributeContentProposalProviders"; //$NON-NLS-1$
public List<IAttributeContentProposalProvider> getContentProposalProviders(XModelObject object, XAttribute attribute) {
List<IAttributeContentProposalProvider> result = EMPTY;
IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(POINT_ID);
IExtension[] es = point.getExtensions();
for (int i = 0; i < es.length; i++) {
IConfigurationElement[] cs = es[i].getConfigurationElements();
for (int j = 0; j < cs.length; j++) {
IAttributeContentProposalProvider provider = null;
try {
Object o = cs[j].createExecutableExtension("class"); //$NON-NLS-1$
provider = (IAttributeContentProposalProvider)o;
} catch (CoreException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
if(provider.isRelevant(object, attribute)) {
if(result == EMPTY) result = new ArrayList<IAttributeContentProposalProvider>();
result.add(provider);
}
}
}
return result;
}
public static IContentProposal makeContentProposal(final String proposal, final String label, final String description) {
return new IContentProposal() {
public String getContent() {
return proposal;
}
public String getDescription() {
return description;
}
public String getLabel() {
return label;
}
public int getCursorPosition() {
return proposal.length();
}
};
}
}