OK, two posts ago I showed that I could make a double-margin in an editor using Patch Fragments. One post ago I used a screencast to demonstrate the basics of writing your own patch fragment.
In this post I will show the code for the double margin.
While in the screencast I messed with org.eclipse.core.resources, for this case, I wrote a patch fragment for org.eclipse.ui.workbench.texteditor. It's my expectation that you have read those last two posts, since I'm only a specific subset here.
First I imported the org.eclipse.ui.workbench.texteditor plug-in, and made a bundle fragment that lived off it.
In the fragment, I created the java package org.eclipse.ui.texteditor, and copied the entire source file for org.eclipse.ui.texteditor.SourceViewerDecoratorSupport from the source project to the new fragment package.
After much searching, I found the thing in SourceViewerDecoratorSupport responsible for painting the margin. It's MarginPainter. Because MarginPainter implements IPainter and PaintListener I hoped writing a delegate that implemented those interfaces would work. e.g.
class TwoColumnMarginPainter implements IPainter, PaintListener {
private final MarginPainter delegate;
public TwoColumnMarginPainter(...) {
this.delegate = new MarginPainter(...);
}
public void initializer() {
delegate.initialize();
}
...
}
Any method defined by the interfaces would be implemented just like initialize: delegate the call to the delegate MarginPainter.
Next, I replaced all uses of MarginPainter with TwoColumnMarginPainter, a grand total of two locations:
From | To |
private MarginPainter fMarginPainter; | private TwoColumnMarginPainter fMarginPainter; |
private void showMargin() { ... if (fMarginPainter == null) { if (fSourceViewer instanceof ITextViewerExtension2) { fMarginPainter= new MarginPainter(fSourceViewer); | private void showMargin() { ... if (fMarginPainter == null) { if (fSourceViewer instanceof ITextViewerExtension2) { System.err.println("Black Magic!"); fMarginPainter= new TwoColumnMarginPainter(fSourceViewer, 20); |
The part where it prints "Black Magic!" was my cue during testing that the patch fragment was taking control of SourceViewerDecoratorSupport.
Once that worked, it was a matter of doubling up in my delegate. Here's the the final implementation of the painter, in full.
package org.eclipse.ui.texteditor;
import org.eclipse.jface.text.IPaintPositionManager;
import org.eclipse.jface.text.IPainter;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.MarginPainter;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
public class TwoColumnMarginPainter implements IPainter, PaintListener {
private final MarginPainter delegate;
private final MarginPainter sibling;
private final int offset;
public TwoColumnMarginPainter(ITextViewer textViewer, int offset) {
delegate = new MarginPainter(textViewer);
sibling = new MarginPainter(textViewer);
this.offset = offset;
}
// @Override
public void setMarginRulerColumn(int width) {
delegate.setMarginRulerColumn(width);
sibling.setMarginRulerColumn(width + offset);
}
// @Override
public void setMarginRulerStyle(int lineStyle) {
delegate.setMarginRulerStyle(lineStyle);
sibling.setMarginRulerStyle(lineStyle);
}
// @Override
public void setMarginRulerWidth(int lineWidth) {
delegate.setMarginRulerWidth(lineWidth);
sibling.setMarginRulerWidth(lineWidth);
}
// @Override
public void setMarginRulerColor(Color color) {
delegate.setMarginRulerColor(color);
sibling.setMarginRulerColor(color);
}
// @Override
public void initialize() {
delegate.initialize();
sibling.initialize();
}
// @Override
public void deactivate(boolean redraw) {
delegate.deactivate(redraw);
sibling.deactivate(redraw);
}
// @Override
public void dispose() {
delegate.dispose();
sibling.dispose();
}
// @Override
public void paint(int reason) {
delegate.paint(reason);
sibling.paint(reason);
}
// @Override
public void paintControl(PaintEvent e) {
delegate.paintControl(e);
sibling.paintControl(e);
}
// @Override
public void setPositionManager(IPaintPositionManager manager) {
delegate.setPositionManager(manager);
sibling.setPositionManager(manager);
}
}
Between this post and the last one you should be able to reproduce the double-margin effect yourself. Let me know if you have any problems or interesting ideas.
2 comments:
A less hacky, more permanent, but admittedly slower way to do this would be to introduce a "MarginPainterFactory" that can be specified by an extension point in the appropriate plugin. Then your plugin fragment could specify an alternate factory and wouldn't have to be a patch fragment.
Sorry for the late reply. I think you would still need the patch fragment because something has to replace the class SourceViewerDecoratorSupport
Post a Comment