blob: c9fe4dcc8d5edd6c6e84c2491a14d727616f1052 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2002, 2009 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
* Dmitry Stadnik (Borland) - contribution for bugzilla 135694
* Dmitry Stadnik (Borland) - contribution for bugzilla 136582
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.editparts;
import java.beans.PropertyChangeEvent;
import java.util.Collections;
import java.util.List;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.Request;
import org.eclipse.gef.requests.DirectEditRequest;
import org.eclipse.gef.tools.DirectEditManager;
import org.eclipse.gmf.runtime.common.core.util.Log;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.common.ui.services.parser.CommonParserHint;
import org.eclipse.gmf.runtime.common.ui.services.parser.IParser;
import org.eclipse.gmf.runtime.common.ui.services.parser.IParserEditStatus;
import org.eclipse.gmf.runtime.common.ui.services.parser.ParserEditStatus;
import org.eclipse.gmf.runtime.common.ui.services.parser.ParserOptions;
import org.eclipse.gmf.runtime.common.ui.services.parser.ParserService;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.EditPolicyRoles;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.LabelDirectEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIDebugOptions;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIPlugin;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIStatusCodes;
import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramColorRegistry;
import org.eclipse.gmf.runtime.diagram.ui.label.ILabelDelegate;
import org.eclipse.gmf.runtime.diagram.ui.label.WrappingLabelDelegate;
import org.eclipse.gmf.runtime.diagram.ui.preferences.IPreferenceConstants;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.diagram.ui.tools.TextDirectEditManager;
import org.eclipse.gmf.runtime.draw2d.ui.figures.WrapLabel;
import org.eclipse.gmf.runtime.draw2d.ui.figures.WrappingLabel;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.ui.services.parser.ISemanticParser;
import org.eclipse.gmf.runtime.emf.ui.services.parser.ParserHintAdapter;
import org.eclipse.gmf.runtime.notation.FontStyle;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.TextAlignment;
import org.eclipse.gmf.runtime.notation.TextStyle;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
/**
* The controller for the text compartment.
*
* @author mmostafa
*/
public class TextCompartmentEditPart extends CompartmentEditPart implements ITextAwareEditPart {
/** the direct edit manager for text editing */
private DirectEditManager manager;
/** the text parser */
protected IParser parser;
/** the text parser options */
private ParserOptions parserOptions;
/** the element to listen to as suggested by the parser*/
private List parserElements = null;
/** the number of icons in the text label */
private int numIcons = 0;
/** Label that is displayed as the tooltip. */
private Label toolTipLabel = new Label();
private ILabelDelegate labelDelegate;
/**
* coinstructor
* @param view the view controlled by this edit part
*/
public TextCompartmentEditPart(EObject model) {
super(model);
}
protected void createDefaultEditPolicies() {
super.createDefaultEditPolicies();
installEditPolicy(
EditPolicy.DIRECT_EDIT_ROLE,
new LabelDirectEditPolicy());
// Text Compartment do not handle creation request for views
removeEditPolicy(EditPolicyRoles.CREATION_ROLE);
}
/**
* Override to use a different figure for this editpart.
* <p>
* IMPORTANT NOTES:
* <li> If you override this to create a different type of figure, you
* should also override {@link #createLabelDelegate()} and make sure you no
* longer call {@link #getLabel()}.
* <li> Do not call {@link #getLabelDelegate()} from within this method. Any
* initialization of the label delegate should be done in the
* {@link #createLabelDelegate()} method.
* </p>
*/
protected IFigure createFigure() {
return createWrapLabel();
}
/**
* @return WrapLabel, the created wrap label
* @deprecated This method has been deprecated to remove the assumption that
* the figure of a <code>TextCompartmentEditPart</code> is a
* <code>WrapLabel</code>. Create your figure in the
* {@link #createFigure()} method instead and don't forget to
* stop calling {@link #getLabel()}.
*/
protected WrapLabel createWrapLabel() {
// alignment properties are set in createLabelDelegate().
return new WrapLabel();
}
/**
* Creates the label delegate that will be used to interact with the label
* figure.
* <p>
* Note: If you have overridden {@link #createFigure()} to create a
* different type of figure, you need to also override this method to return
* the appropriate type of <code>LabelDelegate</code>.
*
* @return the new label delegate
* @since 2.1
*/
protected ILabelDelegate createLabelDelegate() {
// just in case the client has overridden getLabel()...
WrapLabel label = getLabel();
ILabelDelegate newLabelDelegate = null;
if (label != null) {
newLabelDelegate = new WrappingLabelDelegate(label);
} else {
// this should be a WrappingLabel since this is what is created in
// createFigure()...
newLabelDelegate = new WrappingLabelDelegate(
(WrappingLabel) getFigure());
}
newLabelDelegate.setTextJustification(PositionConstants.CENTER);
newLabelDelegate.setAlignment(PositionConstants.CENTER);
newLabelDelegate.setTextAlignment(PositionConstants.TOP);
return newLabelDelegate;
}
public IFigure getFigure() {
if (figure == null) {
setFigure(createFigure());
setLabelDelegate(createLabelDelegate());
}
return figure;
}
/**
* Returns the label delegate that can be used to interact with the label
* figure.
*
* @return the label delegate
* @since 2.1
*/
public ILabelDelegate getLabelDelegate() {
if (labelDelegate == null) {
// this means that getFigure() has never been called as getFigure()
// sets the label delegate. Call getFigure() first.
getFigure();
// check if the label delegate is null, just in case getFigure() was
// overridden
if (labelDelegate == null) {
setLabelDelegate(createLabelDelegate());
}
return labelDelegate;
}
return labelDelegate;
}
/**
* Sets the label delegate.
*
* @param labelDelegate
* the label delegate to be set
* @since 2.1
*/
protected void setLabelDelegate(ILabelDelegate labelDelegate) {
this.labelDelegate = labelDelegate;
}
public Object getAdapter(Class key) {
if (key == ILabelDelegate.class) {
return getLabelDelegate();
}
return super.getAdapter(key);
}
/**
* This should be used instead of getFigure() to get the figure
*
* @return Return the WrapLabel for the TextCompartment
* @deprecated This method has been deprecated to remove the assumption that
* the figure of a <code>TextCompartmentEditPart</code> is a
* <code>WrapLabel</code>. Use {@link #getLabelDelegate()} if
* the behavior you need is available from the label delegate,
* if not use {@link #getFigure()} and cast to the type of label
* that you created in the {@link #createFigure()} method.
*/
public WrapLabel getLabel() {
return (WrapLabel) getFigure();
}
/**
* gets the label Icon for this edit part
* @param index the index to use
* @return Image
*/
protected Image getLabelIcon(int index) {
return null;
}
/**
* gets the label text
* @return the lebel text
*/
protected String getLabelText() {
EObject element = resolveSemanticElement();
return (element == null) ? null
: (getParser() == null) ? null
: getParser().getPrintString(new EObjectAdapter(element),
getParserOptions().intValue());
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart#getEditText()
*/
public String getEditText() {
EObject element = resolveSemanticElement();
return (element == null) ? "" //$NON-NLS-1$
: getParser().getEditString(
new EObjectAdapter(element),
getParserOptions().intValue());
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart#editTextModified(java.lang.String)
*/
public void setLabelText(String text) {
getLabelDelegate().setText(text);
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart#getCompletionProcessor()
*/
public IContentAssistProcessor getCompletionProcessor() {
EObject element = resolveSemanticElement();
if (element != null) {
return getParser().getCompletionProcessor(new EObjectAdapter(element));
}
return null;
}
private boolean canParse() {
return getEditText() != null;
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart#getEditTextValidator()
*/
public ICellEditorValidator getEditTextValidator() {
return new ICellEditorValidator() {
public String isValid(final Object value) {
if (value instanceof String) {
final EObject element = resolveSemanticElement();
final IParser theParser = getParser();
try {
IParserEditStatus isValid = (IParserEditStatus) getEditingDomain()
.runExclusive(new RunnableWithResult.Impl() {
public void run() {
setResult(theParser.isValidEditString(
new EObjectAdapter(element),
(String) value));
}
});
return isValid.getCode() == ParserEditStatus.EDITABLE ? null
: isValid.getMessage();
} catch (InterruptedException e) {
Trace.catching(DiagramUIPlugin.getInstance(),
DiagramUIDebugOptions.EXCEPTIONS_CATCHING,
getClass(), "getEditTextValidator", e); //$NON-NLS-1$
Log.error(DiagramUIPlugin.getInstance(),
DiagramUIStatusCodes.IGNORED_EXCEPTION_WARNING,
"getEditTextValidator", e); //$NON-NLS-1$
}
}
// shouldn't get here
return null;
}
};
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart#getParserOptions()
*/
public final ParserOptions getParserOptions() {
if (parserOptions == null)
parserOptions = buildParserOptions();
return parserOptions;
}
/**
* Builds the parser options.
* @return ParserOptions the parser options
*/
protected ParserOptions buildParserOptions() {
return ParserOptions.NONE;
}
/**
* Builds the parser options.
*/
protected final void refreshParserOptions() {
parserOptions = buildParserOptions();
}
/**
* Determines if the given event affects the paser options
*
* @param evt The event in question
* @return whether the given event affects the parser options
*/
protected boolean isAffectingParserOptions(PropertyChangeEvent evt) {
return false;
}
/**
* Determines if the given Notification affects the paser options
*
* @param evt The notification in question
* @return whether the given notification affects the parser options
*/
protected boolean isAffectingParserOptions(Notification evt) {
return false;
}
/**
* Method getLabelToolTip.
* @return IFigure
*/
protected IFigure getLabelToolTip() {
String text = getToolTipText();
if (text != null && text.length() > 0) {
toolTipLabel.setText(text);
return toolTipLabel;
}
return null;
}
/**
* This method can be overridden in the subclass to return
* text for the tooltip.
* @return String the tooltip
*/
protected String getToolTipText() {
return null;
}
/**
* check if this edit part is editable or not
* @return true or false
*/
protected boolean isEditable() {
EObject element = resolveSemanticElement();
if (element != null && canParse()) {
return true;
}
return false;
}
/**
* performas direct edit
*/
protected void performDirectEdit() {
getManager().show();
}
/**
* Performs direct edit and will initiate another mouse click
* event so that the cursor will appear under the mouse
*
* @param eventLocation
*/
protected void performDirectEdit(Point eventLocation) {
if (getManager().getClass() == TextDirectEditManager.class) {
((TextDirectEditManager) getManager()).show(eventLocation.getSWTPoint());
} else {
performDirectEdit();
}
}
/**
*
* Performs direct edit setting the initial text to be the initialCharacter
*
* @param initialCharacter
*/
private void performDirectEdit(char initialCharacter) {
// Run the TextDirectEditManager show with the initial character
// This will not send an extra mouse click
if (getManager() instanceof TextDirectEditManager) {
((TextDirectEditManager) getManager()).show(initialCharacter);
} else {
performDirectEdit();
}
}
private void showEditPart(){
EditPart parent = getParent();
if (parent!=null){
EditPartViewer viewer = parent.getViewer();
if (viewer!=null){
viewer.reveal(this);
}
}
}
/**
*
* Performs direct edit request based on request type
*
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart#performDirectEditRequest(org.eclipse.gef.requests.DirectEditRequest)
*/
protected void performDirectEditRequest(Request request) {
final Request theRequest = request;
try {
getEditingDomain().runExclusive(new Runnable() {
public void run() {
if (isActive() && isEditable()) {
showEditPart();
// IF the direct edit request has an initial character...
if (theRequest.getExtendedData().get(RequestConstants.REQ_DIRECTEDIT_EXTENDEDDATA_INITIAL_CHAR) instanceof Character) {
Character initialChar = (Character) theRequest.getExtendedData().get(RequestConstants.REQ_DIRECTEDIT_EXTENDEDDATA_INITIAL_CHAR);
performDirectEdit(initialChar.charValue());
} else if ((theRequest instanceof DirectEditRequest) && (getEditText().equals(getLabelText()))) {
DirectEditRequest editRequest = (DirectEditRequest) theRequest;
performDirectEdit(editRequest.getLocation());
} else { // Some other Request
performDirectEdit();
}
}
}
});
} catch (InterruptedException e) {
Trace.catching(DiagramUIPlugin.getInstance(),
DiagramUIDebugOptions.EXCEPTIONS_CATCHING, getClass(),
"performDirectEditRequest", e); //$NON-NLS-1$
Log.error(DiagramUIPlugin.getInstance(),
DiagramUIStatusCodes.IGNORED_EXCEPTION_WARNING,
"performDirectEditRequest", e); //$NON-NLS-1$
}
}
protected void handleNotificationEvent(Notification event) {
Object feature = event.getFeature();
if (NotationPackage.eINSTANCE.getFontStyle_FontColor().equals(feature)) {
Integer c = (Integer) event.getNewValue();
setFontColor(DiagramColorRegistry.getInstance().getColor(c));
}
else if (NotationPackage.eINSTANCE.getFontStyle_Underline().equals(feature))
refreshUnderline();
else if (NotationPackage.eINSTANCE.getFontStyle_StrikeThrough().equals(feature))
refreshStrikeThrough();
else if (NotationPackage.eINSTANCE.getFontStyle_FontHeight().equals(feature) ||
NotationPackage.eINSTANCE.getFontStyle_FontName().equals(feature) ||
NotationPackage.eINSTANCE.getFontStyle_Bold().equals(feature) ||
NotationPackage.eINSTANCE.getFontStyle_Italic().equals(feature)) {
refreshFont();
}
else if (NotationPackage.eINSTANCE.getTextStyle_TextAlignment().equals(feature))
refreshTextAlignment();
else if (isAffectingParserOptions(event)) {
refreshParserOptions();
refreshLabel();
} else if (getParser() != null) {
boolean sematicsAffected = getParser() instanceof ISemanticParser
&& ((ISemanticParser) getParser())
.areSemanticElementsAffected(null, event);
boolean parserAffected = getParser().isAffectingEvent(event,
getParserOptions().intValue());
if (sematicsAffected) {
removeSemanticListeners();
if (resolveSemanticElement() != null) {
addSemanticListeners();
}
}
if (sematicsAffected || parserAffected) {
refreshLabel();
}
}
super.handleNotificationEvent(event);
}
protected void refreshVisuals() {
super.refreshVisuals();
refreshParserOptions();
refreshLabel();
refreshFont();
refreshUnderline();
refreshStrikeThrough();
refreshFontColor();
refreshTextAlignment();
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart#refreshFont()
*/
protected void refreshFont() {
FontStyle style = (FontStyle) getPrimaryView().getStyle(NotationPackage.eINSTANCE.getFontStyle());
FontData fontData = null;
if (style != null) {
fontData = new FontData(
style.getFontName(),
style.getFontHeight(),
(style.isBold() ? SWT.BOLD : SWT.NORMAL) |
(style.isItalic() ? SWT.ITALIC : SWT.NORMAL));
} else {
// initialize font to defaults
fontData =
PreferenceConverter.getFontData(
(IPreferenceStore)getDiagramPreferencesHint().getPreferenceStore(),
IPreferenceConstants.PREF_DEFAULT_FONT);
}
setFont(fontData);
}
protected void setFontColor(Color color) {
getFigure().setForegroundColor(color);
}
protected void addNotationalListeners() {
super.addNotationalListeners();
addListenerFilter("PrimaryView", this, getPrimaryView()); //$NON-NLS-1$
}
protected void addSemanticListeners() {
if (getParser() instanceof ISemanticParser) {
EObject semanticElement = resolveSemanticElement();
parserElements =
((ISemanticParser) getParser()).getSemanticElementsBeingParsed(semanticElement);
for (int i = 0; i < parserElements.size(); i++)
addListenerFilter("SemanticModel" + i, this,(EObject)parserElements.get(i)); //$NON-NLS-1$
} else
super.addSemanticListeners();
}
protected void removeNotationalListeners() {
super.removeNotationalListeners();
removeListenerFilter("PrimaryView"); //$NON-NLS-1$
}
protected void removeSemanticListeners() {
if (parserElements != null) {
for (int i = 0; i < parserElements.size(); i++)
removeListenerFilter("SemanticModel" + i); //$NON-NLS-1$
} else
super.removeSemanticListeners();
}
/**
* getter for the Num Icons
* @return num icons
*/
public int getNumIcons() {
return numIcons;
}
/**
* setter for the num icons
* @param numIcons
*/
public void setNumIcons(int numIcons) {
this.numIcons = numIcons;
}
protected List getModelChildren() {
return Collections.EMPTY_LIST;
}
/*
* (non-Javadoc)
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart#getParser()
*/
public IParser getParser() {
if (parser == null) {
String parserHint = ((View)getModel()).getType();
EObject element = resolveSemanticElement();
if (element != null) {
ParserHintAdapter hintAdapter =
new ParserHintAdapter(element, parserHint);
parser = ParserService.getInstance().getParser(hintAdapter);
}
}
return parser;
}
/**
* Will update the tool tip text for the figure and also the icons for the label. In additional
* it will apply any font constraints to the label based on the type of Text Compartment we
* are dealing with.
* Any body overriding this method should either can this super.refreshLabel() or
* call applyFontContraintsToLabel() to ensure the the proper font constraints are apply to
* the label.
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.TextCompartmentEditPart#refreshLabel()
*/
protected void refreshLabel() {
// refreshes the label text
getLabelDelegate().setText(getLabelText());
// refreshes the label icon(s)
for (int i = 0; i < numIcons; i++)
getLabelDelegate().setIcon(getLabelIcon(i), i);
// refreshes the label tool tip
getFigure().setToolTip(getLabelToolTip());
}
/**
* Refreshes the font underline property
*/
protected void refreshUnderline() {
FontStyle style = (FontStyle) getPrimaryView().getStyle(NotationPackage.eINSTANCE.getFontStyle());
if (style != null)
getLabelDelegate().setTextUnderline(style.isUnderline());
}
/**
* Refreshes the font underline property
*/
protected void refreshStrikeThrough() {
FontStyle style = (FontStyle) getPrimaryView().getStyle(NotationPackage.eINSTANCE.getFontStyle());
if (style != null)
getLabelDelegate().setTextStrikeThrough(style.isStrikeThrough());
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#getAccessibleEditPart()
*/
protected AccessibleEditPart getAccessibleEditPart() {
if (accessibleEP == null)
accessibleEP = new AccessibleGraphicalEditPart() {
public void getName(AccessibleEvent e) {
ILabelDelegate label = getLabelDelegate();
if (label != null) {
e.result = label.getText();
}
}
};
return accessibleEP;
}
/**
* There is no children to text compartments
*
* @param semanticHint
* @return IGraphicalEditPart
*/
public IGraphicalEditPart getChildBySemanticHint(String semanticHint) {
return null;
}
/**
* @return Returns the manager.
*
*/
protected DirectEditManager getManager() {
if (manager == null)
setManager(
new TextDirectEditManager(
this));
return manager;
}
/**
* @param manager The manager to set.
*
*/
protected void setManager(DirectEditManager manager) {
this.manager = manager;
}
/**
* gets the primary child view for this edit part, this is usually used
* by direct edit requests, to see where the edit will happen
* @return <code>View</code>
*/
public View getPrimaryChildView(){
if (getModel()!=null){
View view = (View)getModel();
return ViewUtil.getChildBySemanticHint(view,CommonParserHint.DESCRIPTION);
}
return null;
}
/**
* Refreshes the text alignment property
*/
protected void refreshTextAlignment() {
TextStyle style = (TextStyle) getPrimaryView().getStyle(NotationPackage.eINSTANCE.getTextStyle());
if (style != null) {
if (style.getTextAlignment() == TextAlignment.RIGHT_LITERAL) {
getLabelDelegate().setTextJustification(PositionConstants.RIGHT);
} else if (style.getTextAlignment() == TextAlignment.CENTER_LITERAL) {
getLabelDelegate().setTextJustification(PositionConstants.CENTER);
} else {
// default to TextAlignment.LEFT_LITERAL
getLabelDelegate().setTextJustification(PositionConstants.LEFT);
}
}
}
}