blob: 5043c0c0a8b4c502ac3613b1177f3e9a6c883292 [file] [log] [blame]
/**
* Copyright (c) 2017 Angelo ZERR.
* 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:
* Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
*/
package org.eclipse.jface.text.examples.sources.inlined;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import org.eclipse.jface.text.reconciler.MonoReconciler;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.AnnotationModel;
import org.eclipse.jface.text.source.AnnotationPainter;
import org.eclipse.jface.text.source.IAnnotationAccess;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation;
import org.eclipse.jface.text.source.inlined.InlinedAnnotationSupport;
import org.eclipse.jface.text.source.inlined.LineContentAnnotation;
import org.eclipse.jface.text.source.inlined.LineHeaderAnnotation;
import org.eclipse.jface.text.source.inlined.Positions;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
* An inlined demo with {@link LineHeaderAnnotation} and
* {@link LineContentAnnotation} annotations both:
*
* <ul>
* <li>a status OK, NOK is displayed before the line which starts with 'color:'.
* This status is the result of the content after 'color' which must be a rgb
* content. Here {@link ColorStatusAnnotation} is used.</li>
* <li>a colorized square is displayed before the rgb declaration (inside the
* line content). Here {@link ColorAnnotation} is used.</li>
* </ul>
*
*/
public class InlinedAnnotationDemo {
public static void main(String[] args) throws Exception {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("Inlined annotation demo");
// Create source viewer and initialize the content
ISourceViewer sourceViewer = new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER);
sourceViewer.setDocument(new Document("\ncolor:rgb(255, 255, 0)"), new AnnotationModel());
// Initialize inlined annotations support
InlinedAnnotationSupport support = new InlinedAnnotationSupport();
support.install(sourceViewer, createAnnotationPainter(sourceViewer));
// Refresh inlined annotation in none UI Thread with reconciler.
MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {
@Override
public void setDocument(IDocument document) {
Set<AbstractInlinedAnnotation> annotations = getInlinedAnnotation(sourceViewer, support);
support.updateAnnotations(annotations);
}
@Override
public void reconcile(IRegion partition) {
Set<AbstractInlinedAnnotation> anns = getInlinedAnnotation(sourceViewer, support);
support.updateAnnotations(anns);
}
@Override
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
}
}, false);
reconciler.setDelay(1);
reconciler.install(sourceViewer);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
/**
* Create annotation painter.
*
* @param viewer
* the viewer.
* @return annotation painter.
*/
private static AnnotationPainter createAnnotationPainter(ISourceViewer viewer) {
IAnnotationAccess annotationAccess = new IAnnotationAccess() {
@Override
public Object getType(Annotation annotation) {
return annotation.getType();
}
@Override
public boolean isMultiLine(Annotation annotation) {
return true;
}
@Override
public boolean isTemporary(Annotation annotation) {
return true;
}
};
AnnotationPainter painter = new AnnotationPainter(viewer, annotationAccess);
((ITextViewerExtension2) viewer).addPainter(painter);
return painter;
}
/**
* Returns the inlined annotations list to display in the given viewer.
*
* @param viewer
* the viewer
* @param support
* the inlined annotation suppor.
* @return the inlined annotations list to display in the given viewer.
*/
private static Set<AbstractInlinedAnnotation> getInlinedAnnotation(ISourceViewer viewer,
InlinedAnnotationSupport support) {
IDocument document = viewer.getDocument();
Set<AbstractInlinedAnnotation> annotations = new HashSet<>();
int lineCount = document.getNumberOfLines();
for (int i = 0; i < lineCount; i++) {
String line = getLineText(document, i).trim();
int index = line.indexOf("color:");
if (index == 0) {
String rgb = line.substring(index + "color:".length(), line.length()).trim();
try {
String status = "OK!";
Color color = parse(rgb, viewer.getTextWidget().getDisplay());
if (color != null) {
} else {
status = "ERROR!";
}
// Status color annotation
Position pos = Positions.of(i, document, true);
ColorStatusAnnotation statusAnnotation = support.findExistingAnnotation(pos);
if (statusAnnotation == null) {
statusAnnotation = new ColorStatusAnnotation(pos, viewer);
}
statusAnnotation.setStatus(status);
annotations.add(statusAnnotation);
// Color annotation
if (color != null) {
Position colorPos = new Position(pos.offset + index + "color:".length(), 1);
ColorAnnotation colorAnnotation = support.findExistingAnnotation(colorPos);
if (colorAnnotation == null) {
colorAnnotation = new ColorAnnotation(colorPos, viewer);
}
colorAnnotation.setColor(color);
annotations.add(colorAnnotation);
}
// rgb parameter names annotations
int rgbIndex = line.indexOf("rgb");
if (rgbIndex != -1) {
rgbIndex = rgbIndex + "rgb".length();
int startOffset = pos.offset + rgbIndex;
String rgbContent = line.substring(rgbIndex, line.length());
int startIndex = addRGBParamNameAnnotation("red:", rgbContent, 0, startOffset, viewer, support,
annotations);
if (startIndex != -1) {
startIndex = addRGBParamNameAnnotation("green:", rgbContent, startIndex, startOffset, viewer,
support, annotations);
if (startIndex != -1) {
startIndex = addRGBParamNameAnnotation("blue:", rgbContent, startIndex, startOffset,
viewer, support, annotations);
}
}
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
return annotations;
}
/**
* Add RGB parameter name annotation
*
* @param paramName
* @param rgbContent
* @param startIndex
* @param startOffset
* @param viewer
* @param support
* @param annotations
* @return the current parsed index
*/
private static int addRGBParamNameAnnotation(String paramName, String rgbContent, int startIndex, int startOffset,
ISourceViewer viewer, InlinedAnnotationSupport support, Set<AbstractInlinedAnnotation> annotations) {
char startChar = startIndex == 0 ? '(' : ',';
char[] chars = rgbContent.toCharArray();
for (int i = startIndex; i < chars.length; i++) {
char c = chars[i];
if (c == startChar) {
if (i == chars.length - 1) {
return -1;
}
Position paramPos = new Position(startOffset + i + 1, 1);
LineContentAnnotation colorParamAnnotation = support.findExistingAnnotation(paramPos);
if (colorParamAnnotation == null) {
colorParamAnnotation = new LineContentAnnotation(paramPos, viewer);
}
colorParamAnnotation.setText(paramName);
annotations.add(colorParamAnnotation);
return i + 1;
}
}
return -1;
}
/**
* Parse the given input rgb color and returns an instance of SWT Color and null
* otherwise.
*
* @param input
* the rgb string color
* @param device
* @return the created color and null otherwise.
*/
private static Color parse(String input, Device device) {
Pattern c = Pattern.compile("rgb *\\( *([0-9]+), *([0-9]+), *([0-9]+) *\\)");
Matcher m = c.matcher(input);
if (m.matches()) {
try {
return new Color(device, Integer.valueOf(m.group(1)), // r
Integer.valueOf(m.group(2)), // g
Integer.valueOf(m.group(3))); // b
} catch (Exception e) {
}
}
return null;
}
/**
* Returns the line text.
*
* @param document
* the document.
* @param line
* the line index.
* @return the line text.
*/
private static String getLineText(IDocument document, int line) {
try {
int offset = document.getLineOffset(line);
int length = document.getLineLength(line);
return document.get(offset, length);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}