blob: 68ff9adfa15ac2017f461de4aa17447097d29b93 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2009 Tasktop Technologies 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.tasks.ui.editors;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.dialogs.IInputValidator;
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.IContentProposalProvider;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.mylyn.internal.provisional.commons.ui.CommonTextSupport;
import org.eclipse.mylyn.internal.provisional.commons.ui.CommonThemes;
import org.eclipse.mylyn.internal.tasks.ui.PersonProposalLabelProvider;
import org.eclipse.mylyn.internal.tasks.ui.PersonProposalProvider;
import org.eclipse.mylyn.internal.tasks.ui.editors.EditorUtil;
import org.eclipse.mylyn.internal.tasks.ui.editors.Messages;
import org.eclipse.mylyn.internal.tasks.ui.editors.PersonAttributeEditor;
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTextViewerConfiguration.Mode;
import org.eclipse.mylyn.internal.tasks.ui.editors.RichTextAttributeEditor;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskDataModelEvent;
import org.eclipse.mylyn.tasks.core.data.TaskDataModelEvent.EventKind;
import org.eclipse.mylyn.tasks.core.data.TaskDataModelListener;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.themes.IThemeManager;
/**
* @author Steffen Pingel
* @since 3.0
*/
// TODO EDITOR rename to AttributeUiToolkit?
public class AttributeEditorToolkit {
private final Color colorIncoming;
private Menu menu;
private AbstractRenderingEngine renderingEngine;
private final CommonTextSupport textSupport;
@Deprecated
public IHandlerActivation contentAssistHandlerActivation;
AttributeEditorToolkit(CommonTextSupport textSupport) {
this.textSupport = textSupport;
IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
colorIncoming = themeManager.getCurrentTheme().getColorRegistry().get(CommonThemes.COLOR_INCOMING_BACKGROUND);
}
public void adapt(AbstractAttributeEditor editor) {
if (editor.getControl() instanceof Text || editor.getControl() instanceof CCombo
|| editor instanceof PersonAttributeEditor) {
Control control = (editor instanceof PersonAttributeEditor)
? ((PersonAttributeEditor) editor).getText()
: editor.getControl();
if (control == null) {
// fall back in case getText() returns null
control = editor.getControl();
}
if (!editor.isReadOnly() && hasContentAssist(editor.getTaskAttribute())) {
IContentProposalProvider contentProposalProvider = createContentProposalProvider(editor.getTaskAttribute());
ILabelProvider labelPropsalProvider = createLabelProposalProvider(editor.getTaskAttribute());
if (contentProposalProvider != null && labelPropsalProvider != null) {
ContentAssistCommandAdapter adapter = new ContentAssistCommandAdapter(control,
getContentAdapter(control), contentProposalProvider,
ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, new char[0], true);
adapter.setLabelProvider(labelPropsalProvider);
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
if (editor instanceof PersonAttributeEditor) {
((PersonAttributeEditor) editor).setContentAssistCommandAdapter(adapter);
}
}
}
} else if (editor instanceof RichTextAttributeEditor) {
RichTextAttributeEditor richTextEditor = (RichTextAttributeEditor) editor;
boolean spellCheck = hasSpellChecking(editor.getTaskAttribute());
final SourceViewer viewer = richTextEditor.getViewer();
textSupport.install(viewer, spellCheck);
if (!editor.isReadOnly() && richTextEditor.getMode() == Mode.TASK_RELATION) {
installContentAssistControlDecoration(viewer.getControl());
}
installMenu(viewer.getControl());
} else {
final TextViewer viewer = CommonTextSupport.getTextViewer(editor.getControl());
if (viewer != null) {
textSupport.install(viewer, false);
installMenu(viewer.getControl());
}
}
// for outline
EditorUtil.setMarker(editor.getControl(), editor.getTaskAttribute().getId());
editor.decorate(getColorIncoming());
}
private IControlContentAdapter getContentAdapter(Control control) {
if (control instanceof Combo) {
return new ComboContentAdapter();
} else if (control instanceof Text) {
return new TextContentAdapter();
}
return null;
}
private void installMenu(final Control control) {
if (menu != null) {
control.setMenu(menu);
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
control.setMenu(null);
}
});
}
}
/**
* Adds content assist to the given text field.
*
* @param text
* text field to decorate.
* @param proposalProvider
* instance providing content proposals
* @return the ContentAssistCommandAdapter for the field.
*/
private ControlDecoration installContentAssistControlDecoration(Control control) {
ControlDecoration controlDecoration = new ControlDecoration(control, (SWT.TOP | SWT.LEFT));
controlDecoration.setShowOnlyOnFocus(true);
FieldDecoration contentProposalImage = FieldDecorationRegistry.getDefault().getFieldDecoration(
FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
controlDecoration.setImage(contentProposalImage.getImage());
IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench().getService(IBindingService.class);
controlDecoration.setDescriptionText(NLS.bind(Messages.AttributeEditorToolkit_Content_Assist_Available__X_,
bindingService.getBestActiveBindingFormattedFor(ContentAssistCommandAdapter.CONTENT_PROPOSAL_COMMAND)));
return controlDecoration;
}
/**
* Creates an IContentProposalProvider to provide content assist proposals for the given attribute.
*
* @param attribute
* attribute for which to provide content assist.
* @return the IContentProposalProvider.
*/
private IContentProposalProvider createContentProposalProvider(TaskAttribute attribute) {
Map<String, String> proposals = attribute.getTaskData().getAttributeMapper().getOptions(attribute);
return new PersonProposalProvider(null, attribute.getTaskData(), proposals);
}
private ILabelProvider createLabelProposalProvider(TaskAttribute attribute) {
return new PersonProposalLabelProvider();
}
void dispose() {
// FIXME textSupport.deactivateHandlers();
}
public Color getColorIncoming() {
return colorIncoming;
}
Menu getMenu() {
return menu;
}
/**
* Subclasses that support HTML preview of ticket description and comments override this method to return an
* instance of AbstractRenderingEngine
*
* @return <code>null</code> if HTML preview is not supported for the repository (default)
* @since 2.1
*/
public AbstractRenderingEngine getRenderingEngine(TaskAttribute attribute) {
return renderingEngine;
}
/**
* Called to check if there's content assist available for the given attribute.
*
* @param attribute
* the attribute
* @return true if content assist is available for the specified attribute.
*/
private boolean hasContentAssist(TaskAttribute taskAttribute) {
String type = taskAttribute.getMetaData().getType();
if (TaskAttribute.TYPE_PERSON.equals(type)) {
return true;
} else if (TaskAttribute.TYPE_TASK_DEPENDENCY.equals(type)) {
return true;
}
return false;
}
boolean hasSpellChecking(TaskAttribute taskAttribute) {
String type = taskAttribute.getMetaData().getType();
if (TaskAttribute.TYPE_LONG_RICH_TEXT.equals(type) || TaskAttribute.TYPE_SHORT_RICH_TEXT.equals(type)) {
return true;
}
return false;
}
void setMenu(Menu menu) {
this.menu = menu;
}
public void setRenderingEngine(AbstractRenderingEngine renderingEngine) {
this.renderingEngine = renderingEngine;
}
/**
* Adds input validation to an attribute editor and a controlDecoration if invalid
*
* @since 3.5
*/
public static void createValidator(final AbstractAttributeEditor attributeEditor, Control control,
final IInputValidator validator) {
Assert.isNotNull(validator);
Assert.isNotNull(control);
Assert.isNotNull(attributeEditor);
final ControlDecoration decoration = new ControlDecoration(control, SWT.BOTTOM | SWT.LEFT);
decoration.setMarginWidth(2);
FieldDecoration errorDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(
FieldDecorationRegistry.DEC_ERROR);
decoration.setImage(errorDecoration.getImage());
decoration.hide();
final TaskDataModelListener validationListener = new TaskDataModelListener() {
@Override
public void attributeChanged(TaskDataModelEvent event) {
if (event.getTaskAttribute().equals(attributeEditor.getTaskAttribute())) {
String validationMessage = validator.isValid(attributeEditor.getTaskAttribute().getValue());
if (validationMessage == null) {
decoration.hide();
} else {
decoration.setDescriptionText(validationMessage);
decoration.show();
}
}
}
};
attributeEditor.getModel().addModelListener(validationListener);
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
decoration.dispose();
attributeEditor.getModel().removeModelListener(validationListener);
}
});
validationListener.attributeChanged(new TaskDataModelEvent(attributeEditor.getModel(), EventKind.CHANGED,
attributeEditor.getTaskAttribute()));
}
}