Mar 03
Let’s say that your XML code is invalid in certain line. There is a relative problem marker placed on the vertical ruler. Like the picture below. Now you wish to make the red problem marker click-able, to invoke certain actions, such as pop up quick-fix suggestions. How to do it?
Last week I talked about it in the blog post http://www.frankdu.com/weblog/archives/44. However, there are two issues with the method:
- It takes 3 steps.
- It doesn’t work with a MultiPageEditorPart. This is a huge problem.
Well, now let’s do it in a better way. It takes two steps, and works with MultiPageEditorPart. Here we go:
- Subclass SelectMarkerRulerAction to invoke your desired action. Please refer to the example class PDESelectAnnotationRulerAction.
- In your text editor, override the method createActions, to set the RulerClick action. The example class is PDESourcePage, and the code snipet:
-
-
protected void createActions() {
-
super.createActions();
-
PDESelectAnnotationRulerAction action = new PDESelectAnnotationRulerAction(getBundleForConstructedKeys(), "PDESelectAnnotationRulerAction.", this, getVerticalRuler()); //$NON-NLS-1$
-
setAction(ITextEditorActionConstants.RULER_CLICK, action);
-
}
-
Feb 26
In the text editor, the markers are displayed on the vertical ruler. In Java source editor (CompilationUnitEditor class), you can click a problem marker, then a suggestion list will pop up. It’s pretty user friendly, isn’t it?
Then, how to implement our own clickable annotation marker? Generally the following steps address the issue:
- Add the extension org.eclipse.ui.editorActions.
- Add an editorContribution sub node. Config the contribution.
- Implement an AbstractRulerActionDelegate for the contribution. In its createAction method, return your customized action.
- Implement your customized action by extending SelectMarkerRulerAction. In the action, you may be interested to traverse through annotation model, to invoke the appropriate commands.
Examples are best tutorials. Therefore, let’s take a look at Java source editor in org.eclipse.jdt.ui, step bey step:
1. The editorActions contribution in JDT UI plug-in:
-
-
<extension point="org.eclipse.ui.editorActions">
-
<editorContribution
-
targetID="org.eclipse.jdt.ui.CompilationUnitEditor"
-
id="org.eclipse.jdt.internal.ui.CompilationUnitEditor.ruler.actions">
-
<action
-
label="%JavaSelectRulerAction.label"
-
class="org.eclipse.jdt.internal.ui.javaeditor.JavaSelectRulerAction"
-
actionID="RulerClick"
-
id="org.eclipse.jdt.internal.ui.javaeditor.JavaSelectRulerAction">
-
</action>
-
</editorContribution>
-
</extension>
-
Pay attention to actionID and targetID.
2. The AbstractRulerActionDelegate. It uses template pattern to let you create your own action:
-
-
public class JavaSelectRulerAction extends AbstractRulerActionDelegate {
-
protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) {
-
return new JavaSelectAnnotationRulerAction(JavaEditorMessages.getBundleForConstructedKeys(), "JavaSelectAnnotationRulerAction.", editor, rulerInfo); //$NON-NLS-1$
-
}
-
}
-
3. The SelectMarkerRulerAction. It is needed to access the annotation model. If you don’t need to access annotation model, of course you can use other actions. The Java editor version is JavaSelectAnnotationRulerAction. It contains complicated relations. Therefore, to make it simple, here I paste my simple version:
-
-
public class DataRequestSelectAnnotationRulerAction extends SelectMarkerRulerAction {
-
-
private ITextEditor fTextEditor;
-
private boolean fHasCorrection;
-
-
-
-
-
ITextEditor editor, IVerticalRulerInfo ruler) {
-
super(bundle, prefix, editor, ruler);
-
fTextEditor = editor;
-
}
-
-
@Override
-
public void run() {
-
runWithEvent(null);
-
}
-
-
@Override
-
public void runWithEvent
(Event event
) {
-
if(fHasCorrection){
-
ITextOperationTarget operation= (ITextOperationTarget) fTextEditor.getAdapter(ITextOperationTarget.class);
-
final int opCode= ISourceViewer.QUICK_ASSIST;
-
if (operation != null && operation.canDoOperation(opCode)) {
-
fTextEditor.selectAndReveal(fPosition.getOffset(), fPosition.getLength());
-
operation.doOperation(opCode);
-
}
-
}
-
}
-
-
@Override
-
public void update() {
-
findDataRequestAnnotation();
-
setEnabled(true);
-
-
super.update();
-
}
-
-
private void findDataRequestAnnotation(){
-
fPosition = null;
-
fAnnotation = null;
-
fHasCorrection = false;
-
-
AbstractMarkerAnnotationModel model = this.getAnnotationModel();
-
IAnnotationAccessExtension annotationAccess = this.getAnnotationAccessExtension();
-
-
IDocument document = getDocument();
-
if(model == null)
-
return;
-
-
boolean hasAssistLightbulb = true;
-
-
Iterator iter = model.
getAnnotationIterator();
-
-
-
while(iter.hasNext()){
-
-
-
if(annotation.isMarkedDeleted())
-
continue;
-
-
int annotationLayer = layer;
-
if(annotationAccess != null){
-
annotationLayer = annotationAccess.getLayer(annotation);
-
if(annotationLayer < layer)
-
continue;
-
}
-
-
Position position = model.
getPosition(annotation
);
-
if(!includesRulerLine(position, document))
-
continue;
-
-
boolean isReadOnly = fTextEditor instanceof ITextEditorExtension && ((ITextEditorExtension)fTextEditor).isEditorInputReadOnly();
-
-
if(!isReadOnly && (
-
((hasAssistLightbulb && annotation instanceof TemporaryAnnotation)))
-
){
-
fPosition = position;
-
fAnnotation = annotation;
-
fHasCorrection = true;
-
layer = annotationLayer;
-
return;
-
}
-
-
}
-
}
-
-
}
-
Hope the example above helps.