/** * <copyright> * </copyright> * * */ package org.dresdenocl.language.ocl.resource.ocl.ui; import java.util.ArrayList; import java.util.List; 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.TextAttribute; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.Token; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; /** * An adapter from the Eclipse * <code>org.eclipse.jface.text.rules.ITokenScanner</code> interface to the * generated lexer. */ public class OclTokenScanner implements org.dresdenocl.language.ocl.resource.ocl.ui.IOclTokenScanner { private org.dresdenocl.language.ocl.resource.ocl.IOclTextScanner lexer; private org.dresdenocl.language.ocl.resource.ocl.IOclTextToken currentToken; private List<org.dresdenocl.language.ocl.resource.ocl.IOclTextToken> nextTokens; private int offset; private String languageId; private IPreferenceStore store; private org.dresdenocl.language.ocl.resource.ocl.ui.OclColorManager colorManager; private org.dresdenocl.language.ocl.resource.ocl.IOclTextResource resource; /** * <p> * Creates a new OclTokenScanner. * </p> * * @param resource The resource to scan * @param colorManager A manager to obtain color objects */ public OclTokenScanner(org.dresdenocl.language.ocl.resource.ocl.IOclTextResource resource, org.dresdenocl.language.ocl.resource.ocl.ui.OclColorManager colorManager) { this.resource = resource; this.colorManager = colorManager; this.lexer = new org.dresdenocl.language.ocl.resource.ocl.mopp.OclMetaInformation().createLexer(); this.languageId = new org.dresdenocl.language.ocl.resource.ocl.mopp.OclMetaInformation().getSyntaxName(); org.dresdenocl.language.ocl.resource.ocl.ui.OclUIPlugin plugin = org.dresdenocl.language.ocl.resource.ocl.ui.OclUIPlugin.getDefault(); if (plugin != null) { this.store = plugin.getPreferenceStore(); } this.nextTokens = new ArrayList<org.dresdenocl.language.ocl.resource.ocl.IOclTextToken>(); } public int getTokenLength() { return currentToken.getLength(); } public int getTokenOffset() { return offset + currentToken.getOffset(); } public IToken nextToken() { boolean isOriginalToken = true; if (!nextTokens.isEmpty()) { currentToken = nextTokens.remove(0); isOriginalToken = false; } else { currentToken = lexer.getNextToken(); } if (currentToken == null || !currentToken.canBeUsedForSyntaxHighlighting()) { return Token.EOF; } if (isOriginalToken) { splitCurrentToken(); } TextAttribute textAttribute = null; String tokenName = currentToken.getName(); if (tokenName != null) { org.dresdenocl.language.ocl.resource.ocl.IOclTokenStyle staticStyle = getStaticTokenStyle(); // now call dynamic token styler to allow to apply modifications to the static // style org.dresdenocl.language.ocl.resource.ocl.IOclTokenStyle dynamicStyle = getDynamicTokenStyle(staticStyle); if (dynamicStyle != null) { textAttribute = getTextAttribute(dynamicStyle); } } return new Token(textAttribute); } public void setRange(IDocument document, int offset, int length) { this.offset = offset; try { lexer.setText(document.get(offset, length)); } catch (BadLocationException e) { // ignore this error. It might occur during editing when locations are outdated // quickly. } } public String getTokenText() { return currentToken.getText(); } public int[] convertToIntArray(RGB rgb) { if (rgb == null) { return null; } return new int[] {rgb.red, rgb.green, rgb.blue}; } public org.dresdenocl.language.ocl.resource.ocl.IOclTokenStyle getStaticTokenStyle() { String tokenName = currentToken.getName(); String enableKey = org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.getPreferenceKey(languageId, tokenName, org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.StyleProperty.ENABLE); if (store == null) { return null; } boolean enabled = store.getBoolean(enableKey); if (!enabled) { return null; } String colorKey = org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.getPreferenceKey(languageId, tokenName, org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.StyleProperty.COLOR); RGB foregroundRGB = PreferenceConverter.getColor(store, colorKey); RGB backgroundRGB = null; boolean bold = store.getBoolean(org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.getPreferenceKey(languageId, tokenName, org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.StyleProperty.BOLD)); boolean italic = store.getBoolean(org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.getPreferenceKey(languageId, tokenName, org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.StyleProperty.ITALIC)); boolean strikethrough = store.getBoolean(org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.getPreferenceKey(languageId, tokenName, org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.StyleProperty.STRIKETHROUGH)); boolean underline = store.getBoolean(org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.getPreferenceKey(languageId, tokenName, org.dresdenocl.language.ocl.resource.ocl.ui.OclSyntaxColoringHelper.StyleProperty.UNDERLINE)); return new org.dresdenocl.language.ocl.resource.ocl.mopp.OclTokenStyle(convertToIntArray(foregroundRGB), convertToIntArray(backgroundRGB), bold, italic, strikethrough, underline); } public org.dresdenocl.language.ocl.resource.ocl.IOclTokenStyle getDynamicTokenStyle(org.dresdenocl.language.ocl.resource.ocl.IOclTokenStyle staticStyle) { org.dresdenocl.language.ocl.resource.ocl.mopp.OclDynamicTokenStyler dynamicTokenStyler = new org.dresdenocl.language.ocl.resource.ocl.mopp.OclDynamicTokenStyler(); dynamicTokenStyler.setOffset(offset); org.dresdenocl.language.ocl.resource.ocl.IOclTokenStyle dynamicStyle = dynamicTokenStyler.getDynamicTokenStyle(resource, currentToken, staticStyle); return dynamicStyle; } public TextAttribute getTextAttribute(org.dresdenocl.language.ocl.resource.ocl.IOclTokenStyle tokeStyle) { int[] foregroundColorArray = tokeStyle.getColorAsRGB(); Color foregroundColor = null; if (colorManager != null) { foregroundColor = colorManager.getColor(new RGB(foregroundColorArray[0], foregroundColorArray[1], foregroundColorArray[2])); } int[] backgroundColorArray = tokeStyle.getBackgroundColorAsRGB(); Color backgroundColor = null; if (backgroundColorArray != null) { RGB backgroundRGB = new RGB(backgroundColorArray[0], backgroundColorArray[1], backgroundColorArray[2]); if (colorManager != null) { backgroundColor = colorManager.getColor(backgroundRGB); } } int style = SWT.NORMAL; if (tokeStyle.isBold()) { style = style | SWT.BOLD; } if (tokeStyle.isItalic()) { style = style | SWT.ITALIC; } if (tokeStyle.isStrikethrough()) { style = style | TextAttribute.STRIKETHROUGH; } if (tokeStyle.isUnderline()) { style = style | TextAttribute.UNDERLINE; } return new TextAttribute(foregroundColor, backgroundColor, style); } /** * Tries to split the current token if it contains task items. */ public void splitCurrentToken() { final String text = currentToken.getText(); final String name = currentToken.getName(); final int line = currentToken.getLine(); final int charStart = currentToken.getOffset(); final int column = currentToken.getColumn(); List<org.dresdenocl.language.ocl.resource.ocl.mopp.OclTaskItem> taskItems = new org.dresdenocl.language.ocl.resource.ocl.mopp.OclTaskItemDetector().findTaskItems(text, line, charStart); // this is the offset for the next token to be added int offset = charStart; int itemBeginRelative; List<org.dresdenocl.language.ocl.resource.ocl.IOclTextToken> newItems = new ArrayList<org.dresdenocl.language.ocl.resource.ocl.IOclTextToken>(); for (org.dresdenocl.language.ocl.resource.ocl.mopp.OclTaskItem taskItem : taskItems) { int itemBegin = taskItem.getCharStart(); int itemLine = taskItem.getLine(); int itemColumn = 0; itemBeginRelative = itemBegin - charStart; // create token before task item String textBefore = text.substring(offset - charStart, itemBeginRelative); int textBeforeLength = textBefore.length(); newItems.add(new org.dresdenocl.language.ocl.resource.ocl.mopp.OclTextToken(name, textBefore, offset, textBeforeLength, line, column, true)); // create token for the task item itself offset = offset + textBeforeLength; String itemText = taskItem.getKeyword(); int itemTextLength = itemText.length(); newItems.add(new org.dresdenocl.language.ocl.resource.ocl.mopp.OclTextToken(org.dresdenocl.language.ocl.resource.ocl.mopp.OclTokenStyleInformationProvider.TASK_ITEM_TOKEN_NAME, itemText, offset, itemTextLength, itemLine, itemColumn, true)); offset = offset + itemTextLength; } if (!taskItems.isEmpty()) { // create token after last task item String textAfter = text.substring(offset - charStart); newItems.add(new org.dresdenocl.language.ocl.resource.ocl.mopp.OclTextToken(name, textAfter, offset, textAfter.length(), line, column, true)); } if (!newItems.isEmpty()) { // replace tokens currentToken = newItems.remove(0); nextTokens = newItems; } } }