| /** |
| * Copyright (c) 2017 Angelo ZERR. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * 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()).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); |
| 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.parseInt(m.group(1)), // r |
| Integer.parseInt(m.group(2)), // g |
| Integer.parseInt(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; |
| } |
| } |
| } |