package name.graf.emanuel.testfileeditor.ui;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.JFaceTextUtil;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.CompositeRuler;
import org.eclipse.jface.text.source.LineNumberRulerColumn;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.internal.editors.text.EditorsPlugin;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.rulers.IContributedRulerColumn;
import org.eclipse.ui.texteditor.rulers.RulerColumnDescriptor;
import name.graf.emanuel.testfileeditor.model.TestFile;
import name.graf.emanuel.testfileeditor.model.node.Expected;
import name.graf.emanuel.testfileeditor.model.node.File;
import name.graf.emanuel.testfileeditor.model.node.Node;
import name.graf.emanuel.testfileeditor.model.node.Test;
@SuppressWarnings("restriction")
public class VirtualLineNumberRuler extends LineNumberRulerColumn implements IContributedRulerColumn, Observer {
/**
* @author tstauber
*
* Implements a mouseDoubleClick handler that allows for adding the
* virtual line number that one double clicked on to the markerLines
* list associated with the virtual test file.
*
*/
class MouseHandler implements MouseListener, MouseMoveListener, MouseWheelListener {
@Override
public void mouseScrolled(final MouseEvent e) {
}
@Override
public void mouseMove(final MouseEvent e) {
}
@Override
public void mouseDoubleClick(final MouseEvent e) {
final int lineNo = fparentRuler.getLineOfLastMouseButtonActivity();
final int relativeLineNo = modelLineToRulerLineMap.get(lineNo);
if (lineNo != -1) {
final IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
try {
final int lineOffset = document.getLineOffset(lineNo);
final int newLength = textEditor.getTestFile().addLineNoToMarkerList(lineNo, relativeLineNo);
final TextSelection sel = new TextSelection(lineOffset + newLength, 0);
textEditor.getSelectionProvider().setSelection(sel);
} catch (final BadLocationException exc) {
}
}
}
@Override
public void mouseDown(final MouseEvent e) {
}
@Override
public void mouseUp(final MouseEvent e) {
}
}
private Editor textEditor;
private MouseHandler fMouseHandler;
private RulerColumnDescriptor columnDescriptor;
private ITextViewer textWidget;
private CompositeRuler fparentRuler;
private final Map<Integer, Integer> modelLineToRulerLineMap = new HashMap<>();
private int maxDigits = 0;
public VirtualLineNumberRuler() {
super();
}
@Override
protected int computeNumberOfDigits() {
return maxDigits + 1;
}
@Override
public void columnCreated() {
}
@Override
public void columnRemoved() {
}
@Override
public Control createControl(final CompositeRuler parentRuler, final Composite parentControl) {
fparentRuler = parentRuler;
textWidget = parentRuler.getTextViewer();
final TestFile file = textEditor.getAdapter(TestFile.class);
file.addObserver(this);
update(file, null);
final RGB foreground = getColor(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR);
final RGB background = getColor(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND);
setForeground(EditorsPlugin.getDefault().getSharedTextColors().getColor(foreground));
setBackground(EditorsPlugin.getDefault().getSharedTextColors().getColor(background));
final Control fCanvas = super.createControl(parentRuler, parentControl);
fMouseHandler = new MouseHandler();
fCanvas.addMouseListener(fMouseHandler);
fCanvas.addMouseMoveListener(fMouseHandler);
fCanvas.addMouseWheelListener(fMouseHandler);
return fCanvas;
}
@Override
protected String createDisplayString(int line) {
line = JFaceTextUtil.widgetLine2ModelLine(textWidget, line);
return modelLineToRulerLineMap.containsKey(line) ? modelLineToRulerLineMap.get(line).toString() : "";
}
private RGB getColor(final String key) {
final IPreferenceStore preferenceStore = EditorsUI.getPreferenceStore();
if (preferenceStore.contains(key)) {
return PreferenceConverter.getColor(preferenceStore, key);
}
return PreferenceConverter.getDefaultColor(preferenceStore, key);
}
@Override
public RulerColumnDescriptor getDescriptor() {
return columnDescriptor;
}
@Override
public ITextEditor getEditor() {
return textEditor;
}
@Override
public void setDescriptor(final RulerColumnDescriptor descriptor) {
columnDescriptor = descriptor;
}
@Override
public void setEditor(final ITextEditor editor) {
textEditor = (Editor) editor;
}
@Override
public void update(final Observable o, final Object arg) {
if (o instanceof TestFile) {
final List<Integer> startLineNumbers = new ArrayList<>();
final List<Integer> endLineNumbers = new ArrayList<>();
final TestFile file = (TestFile) o;
final IDocument document = getEditor().getDocumentProvider().getDocument(getEditor().getEditorInput());
final Test[] tests = file.getTests();
try {
for (final Test test : tests) {
final Node[] files = test.getChildren();
Position nodePosition = test.getPosition();
int realLine = document.getLineOfOffset(nodePosition.offset);
endLineNumbers.add(realLine + 1);
for (final Node testNode : files) {
nodePosition = testNode.getPosition();
realLine = document.getLineOfOffset(nodePosition.offset) + 1;
if (testNode instanceof File) {
final String name = testNode.toString();
if (name.endsWith(".cpp") || name.endsWith(".h") || name.endsWith(".hpp")) {
startLineNumbers.add(realLine);
} else {
endLineNumbers.add(realLine);
}
} else if (testNode instanceof Expected) {
startLineNumbers.add(realLine);
} else {
endLineNumbers.add(realLine);
}
}
}
} catch (final BadLocationException e) {
e.printStackTrace();
}
modelLineToRulerLineMap.clear();
int largestNumber = 0;
final int lines = document.getNumberOfLines() + 1;
boolean inFile = false;
int rulerLine = 1;
for (int line = 1; line < lines; ++line) {
if (startLineNumbers.contains(line)) {
inFile = true;
rulerLine = 1;
continue;
} else if (endLineNumbers.contains(line)) {
inFile = false;
} else if (inFile) {
if (rulerLine > largestNumber) {
largestNumber = rulerLine;
}
modelLineToRulerLineMap.put(line - 1, rulerLine++);
}
}
maxDigits = Integer.toString(largestNumber).length();
redraw();
}
}
}