| /******************************************************************************* |
| * Copyright (c) 2009, 2018 Borland Software Corporation and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Borland Software Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.m2m.internal.qvt.oml.editor.ui.colorer; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.preference.PreferenceConverter; |
| import org.eclipse.jface.resource.StringConverter; |
| import org.eclipse.jface.text.TextAttribute; |
| import org.eclipse.jface.text.rules.Token; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.RGB; |
| |
| |
| public class QVTColorManager extends IQVTColors { |
| |
| public interface IHighlightingChanged { |
| |
| void highlightingChanged(ColorDescriptor cd); |
| } |
| |
| public class ColorDescriptor { |
| |
| private TextAttribute fAttribute; |
| |
| private Highlighting fHighlighting; |
| |
| private Token fToken; |
| |
| private final String fDisplayName; |
| |
| private final String fEnabledKey; |
| |
| private final String fBoldKey; |
| |
| private final String fItalicKey; |
| |
| private final String fColorKey; |
| |
| private final String fStrikethroughKey; |
| |
| private final String fUnderlineKey; |
| |
| private final String fKey; |
| |
| public ColorDescriptor(String key, String displayName, boolean canBeDisabled) { |
| fKey = key; |
| String baseKey = BASE_COLORS_KEY_PREFIX + key; |
| fDisplayName = displayName; |
| |
| fBoldKey = baseKey + BOLD_SUFFIX; |
| fItalicKey = baseKey + ITALIC_SUFFIX; |
| fColorKey = baseKey + COLOR_SUFFIX; |
| fStrikethroughKey = baseKey + STRIKETHROUGH_SUFFIX; |
| fUnderlineKey = baseKey + UNDERLINE_SUFFIX; |
| fEnabledKey = canBeDisabled ? baseKey + ENABLED_SUFFIX : null; |
| } |
| |
| public String key() { |
| return fKey; |
| } |
| |
| public boolean canBeDisabled() { |
| return fEnabledKey != null; |
| } |
| |
| public String getDisplayName() { |
| return fDisplayName; |
| } |
| |
| public String getEnabledKey() { |
| return fEnabledKey; |
| } |
| |
| public String getBoldKey() { |
| return fBoldKey; |
| } |
| |
| public String getItalicKey() { |
| return fItalicKey; |
| } |
| |
| public String getStrikethroughKey() { |
| return fStrikethroughKey; |
| } |
| |
| public String getUnderlineKey() { |
| return fUnderlineKey; |
| } |
| |
| public String getColorKey() { |
| return fColorKey; |
| } |
| |
| public Highlighting getHighlighting() { |
| return fHighlighting; |
| } |
| |
| public boolean isAffectedBy(String property) { |
| return property.equals(getColorKey()) || property.equals(getBoldKey()) || property.equals(getEnabledKey()) |
| || property.equals(getItalicKey()) || property.equals(getStrikethroughKey()) |
| || property.equals(getUnderlineKey()); |
| } |
| |
| /** |
| * UI thread only |
| */ |
| public TextAttribute createTextAttribute() { |
| if (fAttribute != null) { |
| return fAttribute; |
| } |
| |
| addColor(getColorKey()); |
| |
| int style = fStore.getBoolean(getBoldKey()) ? SWT.BOLD : SWT.NORMAL; |
| |
| if (fStore.getBoolean(getItalicKey())) |
| style |= SWT.ITALIC; |
| |
| if (fStore.getBoolean(getStrikethroughKey())) |
| style |= TextAttribute.STRIKETHROUGH; |
| |
| if (fStore.getBoolean(getUnderlineKey())) |
| style |= TextAttribute.UNDERLINE; |
| |
| Color color = fColorManager.getColor(PreferenceConverter.getColor(fStore, getColorKey())); |
| |
| fAttribute = new TextAttribute(color, null, style); |
| return fAttribute; |
| } |
| |
| /** |
| * UI thread only |
| */ |
| public Highlighting createHighlighting() { |
| if (fHighlighting != null) { |
| return fHighlighting; |
| } |
| |
| boolean isEnabled = canBeDisabled() ? fStore.getBoolean(getEnabledKey()) : true; |
| fHighlighting = new Highlighting(createTextAttribute(), isEnabled); |
| return fHighlighting; |
| } |
| |
| public Token createToken() { |
| if (fToken != null) { |
| return fToken; |
| } |
| fToken = new Token(createTextAttribute()); |
| return fToken; |
| } |
| |
| public void disposeColor() { |
| if (fAttribute != null) { |
| removeColor(getColorKey()); |
| fAttribute = null; |
| } |
| } |
| |
| public TextAttribute getTextAttribute() { |
| return fAttribute; |
| } |
| |
| public void setTextAttribute(TextAttribute ta) { |
| fAttribute = ta; |
| if (fHighlighting != null) { |
| fHighlighting.setTextAttribute(ta); |
| } |
| if (fToken != null) { |
| fToken.setData(ta); |
| } |
| } |
| } |
| |
| public class Highlighting { |
| |
| private TextAttribute fTextAttribute; |
| |
| private boolean fIsEnabled; |
| |
| public Highlighting(TextAttribute textAttribute, boolean isEnabled) { |
| setTextAttribute(textAttribute); |
| setEnabled(isEnabled); |
| } |
| |
| public TextAttribute getTextAttribute() { |
| return fTextAttribute; |
| } |
| |
| public void setTextAttribute(TextAttribute textAttribute) { |
| fTextAttribute = textAttribute; |
| } |
| |
| public boolean isEnabled() { |
| return fIsEnabled; |
| } |
| |
| public void setEnabled(boolean isEnabled) { |
| fIsEnabled = isEnabled; |
| } |
| } |
| |
| ListenerList fColorChangedListeners = new ListenerList(); |
| |
| private final List<ColorDescriptor> fDescriptors; |
| |
| private final Map<String, DefaultColoring> fKey2Default; |
| |
| private final Map<String, ColorDescriptor> fKey2Descriptor; |
| |
| |
| private IPreferenceStore fStore; |
| |
| private ColorManager fColorManager; |
| |
| |
| public QVTColorManager(IPreferenceStore store, ColorManager manager) { |
| fStore = store; |
| fColorManager = manager; |
| fDescriptors = new ArrayList<ColorDescriptor>(); |
| fKey2Descriptor = new HashMap<String, ColorDescriptor>(); |
| fKey2Default = new HashMap<String, DefaultColoring>(); |
| initDescriptors(); |
| } |
| |
| void forceInitialize() { |
| for (ColorDescriptor next : fDescriptors) { |
| next.createToken(); |
| } |
| } |
| |
| public ColorDescriptor getColor(String id) { |
| return fKey2Descriptor.get(id); |
| } |
| |
| private int addDescriptor(String key, String name, boolean canBeDisabled, DefaultColoring defaultSettings) { |
| assert key != null && name != null && defaultSettings != null; |
| |
| ColorDescriptor cd = new ColorDescriptor(key, name, canBeDisabled); |
| fKey2Descriptor.put(key, cd); |
| fDescriptors.add(cd); |
| |
| fKey2Default.put(key, defaultSettings); |
| |
| return fDescriptors.size(); |
| } |
| |
| private void initDescriptors() { |
| addDescriptor(MULTILINE_COMMENT, Messages.SemanticKey_multiLineComment, false, |
| new DefaultColoring(new RGB(63, 127, 95), false, true, false, false)); |
| addDescriptor(LINE_COMMENT, Messages.SemanticKey_singleLineComment, false, |
| new DefaultColoring(new RGB(63, 127, 95), false, true, false, false)); |
| addDescriptor(TASK_TAG, Messages.SemanticKey_taskTags, false, |
| new DefaultColoring(new RGB(127, 159, 191), true, false, false, false)); |
| addDescriptor(DOC_OTHERS, Messages.SemanticKey_Others, true, |
| new DefaultColoring(new RGB(63, 95, 191), false, false, false, false)); |
| addDescriptor(DOC_TAG, Messages.SemanticKey_DocTags, true, |
| new DefaultColoring(new RGB(63, 95, 191), false, false, false, false)); |
| addDescriptor(FATAL_ASSERT, Messages.SemanticKey_FatalAssertion, true, |
| new DefaultColoring(new RGB(255, 0, 0), false, false, false, false)); |
| addDescriptor(KEYWORD, Messages.SemanticKey_Keywords, false, |
| new DefaultColoring(new RGB(127, 0, 85), true, false, false, false)); |
| |
| addDescriptor(STRING, Messages.SemanticKey_Strings, false, |
| new DefaultColoring(new RGB(42, 0, 255), false, false, false, false)); |
| addDescriptor(NUMBER, Messages.SemanticKey_Numbers, false, |
| new DefaultColoring(new RGB(0, 128, 0), false, false, false, false)); |
| addDescriptor(DEFAULT, Messages.SemanticKey_Others, false, |
| new DefaultColoring(new RGB(0, 0, 0), false, false, false, false)); |
| // TODO - no urgent now |
| // addDescriptor(VARIABLE, "Local variable", true, |
| // new DefaultColoring(new RGB(13, 100, 0), false, false, false, false)); |
| // addDescriptor(OPERATION_PARAMETER, "Operation parameter", true, |
| // new DefaultColoring(new RGB(13, 100, 0), false, false, false, false)); |
| addDescriptor(MODEL_PARAMETER, Messages.SemanticKey_ModelParameters, true, |
| new DefaultColoring(new RGB(128, 128, 0), false, false, false, false)); |
| addDescriptor(MODULE_ELEMENT, Messages.SemanticKey_ModuleElements, true, |
| new DefaultColoring(new RGB(111, 0, 74), false, false, false, false)); |
| addDescriptor(RESULT_VARIABLE, Messages.SemanticKey_ResultVar, true, |
| new DefaultColoring(new RGB(0, 0, 160), true, false, false, false)); |
| addDescriptor(SELF_VARIABLE, Messages.SemanticKey_SelfVar, true, |
| new DefaultColoring(new RGB(0, 0, 160), true, false, false, false)); |
| |
| addDescriptor(INTERMEDIATE_DATA, Messages.SemanticKey_IntermData, true, |
| new DefaultColoring(new RGB(108, 108, 108), false, false, false, false)); |
| |
| addDescriptor(USER_MODEL_ELEMENT, Messages.SemanticKey_UserModelElements, true, |
| new DefaultColoring(new RGB(0, 0, 192), false, false, false, false)); |
| |
| addDescriptor(STDLIB_ELEMENT, Messages.SemanticKey_StdlibElements, true, |
| new DefaultColoring(new RGB(0, 0, 0), false, true, false, false)); |
| } |
| |
| public void initializeDefaults() { |
| |
| for (String nextColorKey : fKey2Default.keySet()) { |
| DefaultColoring settings = fKey2Default.get(nextColorKey); |
| initDefault(nextColorKey, settings); |
| } |
| } |
| |
| private static class DefaultColoring { |
| private RGB rgb; |
| private boolean bold; |
| private boolean italic; |
| private boolean underline; |
| private boolean strikethrough; |
| |
| public DefaultColoring(RGB rgb, boolean bold, boolean italic, |
| boolean underline, boolean strikethrough) { |
| this.rgb = rgb; |
| this.bold = bold; |
| this.italic = italic; |
| this.underline = underline; |
| this.strikethrough = strikethrough; |
| } |
| |
| public RGB getRgb() { |
| return rgb; |
| } |
| |
| public boolean isBold() { |
| return bold; |
| } |
| |
| public boolean isItalic() { |
| return italic; |
| } |
| |
| public boolean isUnderline() { |
| return underline; |
| } |
| |
| public boolean isStrikethrough() { |
| return strikethrough; |
| } |
| } |
| |
| |
| private void initDefault(String id, DefaultColoring defaultSettings) { |
| ColorDescriptor cd = getColor(id); |
| assert cd != null; |
| |
| PreferenceConverter.setDefault(fStore, cd.getColorKey(), defaultSettings.getRgb()); |
| fStore.setDefault(cd.getBoldKey(), defaultSettings.isBold()); |
| fStore.setDefault(cd.getItalicKey(), defaultSettings.isItalic()); |
| fStore.setDefault(cd.getUnderlineKey(), defaultSettings.isUnderline()); |
| fStore.setDefault(cd.getStrikethroughKey(), defaultSettings.isStrikethrough()); |
| if (cd.canBeDisabled()) { |
| fStore.setDefault(cd.getEnabledKey(), true); |
| } |
| } |
| |
| public void dispose() { |
| for (ColorDescriptor cd : fDescriptors) { |
| cd.disposeColor(); |
| } |
| } |
| |
| public void propertyChange(PropertyChangeEvent event) { |
| if (fStore == null) { |
| return; |
| } |
| |
| String property = event.getProperty(); |
| |
| for (ColorDescriptor cd : fDescriptors) { |
| if (cd.getColorKey().equals(property)) { |
| adaptToTextForegroundChange(cd, event); |
| notifyStyleChanged(cd); |
| break; |
| } |
| |
| if (cd.getBoldKey().equals(property)) { |
| adaptToTextStyleChange(cd, event, SWT.BOLD); |
| notifyStyleChanged(cd); |
| break; |
| } |
| |
| if (cd.getItalicKey().equals(property)) { |
| adaptToTextStyleChange(cd, event, SWT.ITALIC); |
| notifyStyleChanged(cd); |
| break; |
| } |
| |
| if (cd.getStrikethroughKey().equals(property)) { |
| adaptToTextStyleChange(cd, event, TextAttribute.STRIKETHROUGH); |
| notifyStyleChanged(cd); |
| break; |
| } |
| |
| if (cd.getUnderlineKey().equals(property)) { |
| adaptToTextStyleChange(cd, event, TextAttribute.UNDERLINE); |
| notifyStyleChanged(cd); |
| break; |
| } |
| |
| if (cd.canBeDisabled() && cd.getEnabledKey().equals(property)) { |
| adaptToEnablementChange(cd.getHighlighting(), event); |
| notifyStyleChanged(cd); |
| break; |
| } |
| } |
| } |
| |
| public void addHighlightingChangedListener(IHighlightingChanged listener) { |
| fColorChangedListeners.add(listener); |
| } |
| |
| public void removeHighlightingChangedListener(IHighlightingChanged listener) { |
| fColorChangedListeners.remove(listener); |
| } |
| |
| private void notifyStyleChanged(ColorDescriptor cd) { |
| Object[] listeners = fColorChangedListeners.getListeners(); |
| for (int i = 0; i < listeners.length; ++i) { |
| ((IHighlightingChanged) listeners[i]).highlightingChanged(cd); |
| } |
| } |
| |
| private void adaptToEnablementChange(Highlighting highlighting, PropertyChangeEvent event) { |
| if (highlighting == null) { |
| return; |
| } |
| Object value = event.getNewValue(); |
| boolean eventValue; |
| if (value instanceof Boolean) |
| eventValue = ((Boolean) value).booleanValue(); |
| else if (IPreferenceStore.TRUE.equals(value)) |
| eventValue = true; |
| else |
| eventValue = false; |
| highlighting.setEnabled(eventValue); |
| } |
| |
| private void adaptToTextForegroundChange(ColorDescriptor descriptor, PropertyChangeEvent event) { |
| if (descriptor.getTextAttribute() == null) { |
| return; |
| } |
| RGB rgb = null; |
| |
| Object value = event.getNewValue(); |
| if (value instanceof RGB) |
| rgb = (RGB) value; |
| else if (value instanceof String) |
| rgb = StringConverter.asRGB((String) value); |
| |
| if (rgb != null) { |
| |
| String property = event.getProperty(); |
| Color color = fColorManager.getColor(property); |
| |
| if ((color == null || !rgb.equals(color.getRGB()))) { |
| fColorManager.unbindColor(property); |
| fColorManager.bindColor(property, rgb); |
| color = fColorManager.getColor(property); |
| } |
| |
| TextAttribute oldAttr = descriptor.getTextAttribute(); |
| descriptor.setTextAttribute(new TextAttribute(color, oldAttr.getBackground(), oldAttr.getStyle())); |
| } |
| } |
| |
| private void adaptToTextStyleChange(ColorDescriptor descriptor, PropertyChangeEvent event, int styleAttribute) { |
| if (descriptor.getTextAttribute() == null) { |
| return; |
| } |
| boolean eventValue = false; |
| Object value = event.getNewValue(); |
| if (value instanceof Boolean) |
| eventValue = ((Boolean) value).booleanValue(); |
| else if (IPreferenceStore.TRUE.equals(value)) |
| eventValue = true; |
| |
| TextAttribute oldAttr = descriptor.getTextAttribute(); |
| boolean activeValue = (oldAttr.getStyle() & styleAttribute) == styleAttribute; |
| |
| if (activeValue != eventValue) |
| descriptor.setTextAttribute(new TextAttribute(oldAttr.getForeground(), oldAttr.getBackground(), |
| eventValue ? oldAttr.getStyle() | styleAttribute : oldAttr.getStyle() & ~styleAttribute)); |
| } |
| |
| private void addColor(String colorKey) { |
| if (fColorManager != null && colorKey != null && fColorManager.getColor(colorKey) == null) { |
| RGB rgb = PreferenceConverter.getColor(fStore, colorKey); |
| fColorManager.unbindColor(colorKey); |
| fColorManager.bindColor(colorKey, rgb); |
| } |
| } |
| |
| private void removeColor(String colorKey) { |
| fColorManager.unbindColor(colorKey); |
| } |
| |
| public boolean isAffected(PropertyChangeEvent event) { |
| String property = event.getProperty(); |
| for (ColorDescriptor cd : fDescriptors) { |
| if (cd.isAffectedBy(property)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public ColorDescriptor[] getSemanticHighlightings() { |
| return fDescriptors.toArray(new ColorDescriptor[fDescriptors.size()]); |
| } |
| |
| int getDescriptorIndex(ColorDescriptor colorDescriptor) { |
| return fDescriptors.indexOf(colorDescriptor); |
| } |
| } |