package org.jbehave.eclipse.preferences; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import org.apache.commons.lang.ArrayUtils; import org.eclipse.jface.preference.ColorSelector; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.jface.text.CursorLinePainter; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.IWorkbench; import org.jbehave.eclipse.Activator; import org.jbehave.eclipse.editor.text.ColorManager; import org.jbehave.eclipse.editor.text.style.StyleRangeConverter; import org.jbehave.eclipse.editor.text.style.TextStyle; import org.jbehave.eclipse.editor.text.style.TextStyleLabelProvider; import org.jbehave.eclipse.editor.text.style.TextStylePreferences; import org.jbehave.eclipse.editor.text.style.TextStyleTreeBuilder; import org.jbehave.eclipse.editor.text.style.TextStyleTreeContentProvider; import org.jbehave.eclipse.swt.SWTResourceManager; import org.jbehave.eclipse.util.New; public class EditorColorPreferencePage extends PreferencePage implements org.eclipse.ui.IWorkbenchPreferencePage { private ColorManager colorManager; private StyleRangeConverter styleRangeConverter; // private Combo themeCombo; private TreeViewer keywordTree; private Button customForegroundChk; private ColorSelector customForegroundButton; private Button customBackgroundChk; private ColorSelector customBackgroundButton; private Button customItalicChk; private Button customBoldChk; private TextViewer previewStyledText; // private TextStyle current; private TextStyle rootStyle; // private Map<String, TextStyle> themesLoaded = New.hashMap(); /** * Create the preference page. */ public EditorColorPreferencePage() { } /** * Initialize the preference page. */ public void init(IWorkbench workbench) { // Initialize the preference page setPreferenceStore(Activator.getDefault().getPreferenceStore()); } /** * Create contents of the preference page. * @param parent */ @Override public Control createContents(Composite parent) { colorManager = new ColorManager(); styleRangeConverter = new StyleRangeConverter(colorManager); SelectionListener styleChangedListener = new SelectionListener() { public void widgetSelected(SelectionEvent event) { adjustButtonStatusAndColors(); updatePreview(); } public void widgetDefaultSelected(SelectionEvent event) { } }; IPropertyChangeListener styleChangedPropertyListener = new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { ColorSelector selector = (ColorSelector)event.getSource(); selector.getButton().setToolTipText(selector.getColorValue().toString()); adjustButtonStatusAndColors(); updatePreview(); } }; ResourceBundle bundle = PreferencesMessages.getBundle(); Composite container = new Composite(parent, SWT.NULL); container.setLayout(new GridLayout(6, false)); // ~~ row 1 Label lblTheme = new Label(container, SWT.NONE); lblTheme.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblTheme.setText("Theme"); themeCombo = new Combo(container, SWT.NONE|SWT.READ_ONLY); themeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 4, 1)); themeCombo.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); } public void widgetSelected(SelectionEvent event) { int selectionIndex = themeCombo.getSelectionIndex(); setCurrentTheme(themeCombo.getItem(selectionIndex)); } }); new Label(container, SWT.NONE); // ~~ row 2 Label lblCurrentLine = new Label(container, SWT.NONE); lblCurrentLine.setText("Current line marker:"); currentLineColor = new ColorSelector(container); currentLineColor.addListener(styleChangedPropertyListener); currentLineColor.getButton().setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); Label lblCurrentLineToolTip = new Label(container, SWT.NONE); lblCurrentLineToolTip.setText("(Change the caret position in the preview for feedback)"); new Label(container, SWT.NONE); new Label(container, SWT.NONE); // keywordTree = new TreeViewer(container, SWT.SINGLE |SWT.BORDER); Tree tree = keywordTree.getTree(); GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 4, 5); gridData.widthHint = 80; gridData.heightHint = 30; tree.setLayoutData(gridData); keywordTree.setLabelProvider(new TextStyleLabelProvider(bundle, "text-style.")); keywordTree.setContentProvider(new TextStyleTreeContentProvider()); keywordTree.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { ISelection selection = event.getSelection(); if(selection instanceof IStructuredSelection) { IStructuredSelection structured = (IStructuredSelection)selection; Object firstElement = structured.getFirstElement(); setCurrentTextStyle((TextStyle)firstElement); } } }); customForegroundChk = new Button(container, SWT.CHECK); customForegroundChk.setText("Foreground"); customForegroundChk.addSelectionListener(styleChangedListener); customForegroundButton = new ColorSelector(container); customForegroundButton.addListener(styleChangedPropertyListener); customBackgroundChk = new Button(container, SWT.CHECK); customBackgroundChk.setText("Background"); customBackgroundChk.addSelectionListener(styleChangedListener); customBackgroundButton = new ColorSelector(container); customBackgroundButton.addListener(styleChangedPropertyListener); customItalicChk = new Button(container, SWT.CHECK); customItalicChk.setFont(SWTResourceManager.getFont("Lucida Grande", 11, SWT.ITALIC)); customItalicChk.setText("Italic"); customItalicChk.addSelectionListener(styleChangedListener); new Label(container, SWT.NONE); customBoldChk = new Button(container, SWT.CHECK); customBoldChk.setFont(SWTResourceManager.getFont("Lucida Grande", 11, SWT.BOLD)); customBoldChk.setText("Bold"); customBoldChk.addSelectionListener(styleChangedListener); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); Label lblPreview = new Label(container, SWT.NONE); lblPreview.setText("Preview"); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); previewStyledText = new TextViewer(container, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.READ_ONLY); GridData gridData2 = new GridData(SWT.FILL, SWT.FILL, true, true, 6, 1); gridData2.widthHint = 80; gridData2.heightHint = 140; previewStyledText.getControl().setLayoutData(gridData2); cursorLinePainter = new CursorLinePainter(previewStyledText); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); previewStyledText.addPainter(cursorLinePainter); initialize(); return container; } @Override public void dispose() { colorManager.dispose(); super.dispose(); } private Color getLineBackground() { return colorManager.getColor(currentLineColor.getColorValue()); } /** * Initial values. */ protected void initialize() { previewStyledText.setDocument(new Document(createText())); IPreferenceStore store = getPreferenceStore(); String inlinedThemes = store.getString(PreferenceConstants.THEMES); String selectedTheme = store.getString(PreferenceConstants.THEME); String[] themes = inlinedThemes.split(","); themeCombo.setItems(themes); themeCombo.select(ArrayUtils.indexOf(themes, selectedTheme)); setCurrentTheme(selectedTheme); } /** * */ private void setCurrentTheme(String theme) { rootStyle = themesLoaded.get(theme); if(rootStyle==null) { rootStyle = new TextStyleTreeBuilder().createTree(theme); TextStylePreferences.load(rootStyle, getPreferenceStore()); themesLoaded.put(theme, rootStyle); } keywordTree.setInput(new Object[] { rootStyle }); currentLineColor.setColorValue(rootStyle.getCurrentLineHighlight()); setCurrentTextStyle(rootStyle); updatePreview(); } /** * */ private void setCurrentTextStyle(TextStyle textStyle) { if(textStyle==null) { return; } this.current = textStyle; customBackgroundChk.setSelection(current.hasBackground()); customForegroundChk.setSelection(current.hasForeground()); customBackgroundButton.setColorValue(current.getBackgroundOrDefault()); customForegroundButton.setColorValue(current.getForegroundOrDefault()); customBoldChk.setSelection(current.isBold()); customItalicChk.setSelection(current.isItalic()); adjustButtonStatusAndColors(); } protected void adjustButtonStatusAndColors() { customForegroundButton.setEnabled(customForegroundChk.getSelection()); if(customForegroundChk.getSelection()) { current.setForeground(customForegroundButton.getColorValue()); } else { current.setForeground(null); } customBackgroundButton.setEnabled(customBackgroundChk.getSelection()); if(customBackgroundChk.getSelection()) { current.setBackground(customBackgroundButton.getColorValue()); } else { current.setBackground(null); } current.setBold(customBoldChk.getSelection()); current.setItalic(customItalicChk.getSelection()); rootStyle.setCurrentLineHighlight(currentLineColor.getColorValue()); } protected void storeModifications() { IPreferenceStore store = getPreferenceStore(); for(TextStyle rootStyle : themesLoaded.values()) { TextStylePreferences.store(rootStyle, store); } String theme = rootStyle.getPath(); store.setValue(PreferenceConstants.THEME, theme); // fire an overall change, to have a unique property notification hook // instead of one per property store.firePropertyChangeEvent(PreferenceConstants.THEME_CHANGED, theme, theme); } @Override public boolean performOk() { storeModifications(); return super.performOk(); } private static boolean DumpCurrentStyleOnApply = false; private ColorSelector currentLineColor; private CursorLinePainter cursorLinePainter; @Override protected void performApply() { if(DumpCurrentStyleOnApply) { dumpCurrentStyle(); } storeModifications(); super.performApply(); } @Override protected void performDefaults() { TextStylePreferences.loadFromDefault(rootStyle, getPreferenceStore()); setCurrentTextStyle(rootStyle); updatePreview(); super.performDefaults(); } private void updatePreview() { cursorLinePainter.setHighlightColor(getLineBackground()); previewStyledText.getTextWidget().setBackground(colorManager.getColor(rootStyle.getBackgroundOrDefault())); previewStyledText.getTextWidget().setForeground(colorManager.getColor(rootStyle.getForegroundOrDefault())); previewStyledText.getTextWidget().setStyleRanges(createStyleRanges()); } /** * Iterate over all fragments and generate corresponding text for the preview. */ private String createText() { StringBuilder builder = new StringBuilder(); for(Fragment f : fragments()) { builder.append(f.content); } return builder.toString(); } /** * Iterate over all fragments and generate corresponding styles for the preview. */ private StyleRange[] createStyleRanges() { Map<String, TextStyle> map = rootStyle.createMap(); List<StyleRange> ranges = New.arrayList(); int offset = 0; for(Fragment f : fragments()) { TextStyle style = map.get(f.key); int length = f.content.length(); StyleRange styleRange = styleRangeConverter.createStyleRange(style, offset, length); ranges.add(styleRange); offset += length; } return ranges.toArray(new StyleRange[ranges.size()]); } /** * The fragments used for the preview: content with its associated style. * @return */ private List<Fragment> fragments() { return Arrays.asList( f(TextStyle.DEFAULT, "A story is a collection of scenarios\n\n"),// f(TextStyle.NARRATIVE_KEYWORD, "Narrative:\n"),// f(TextStyle.NARRATIVE_KEYWORD, "In order to "),// f(TextStyle.NARRATIVE_DEFAULT, "communicate effectively to the business some functionality\n"),// f(TextStyle.NARRATIVE_KEYWORD, "As a "),// f(TextStyle.NARRATIVE_DEFAULT, "development team\n"),// f(TextStyle.NARRATIVE_KEYWORD, "I want to "),// f(TextStyle.NARRATIVE_DEFAULT, "use Behaviour-Driven Development\n"),// f(TextStyle.DEFAULT, "\n"),// f(TextStyle.SCENARIO_KEYWORD, "Scenario: "),// f(TextStyle.SCENARIO_DEFAULT, " A scenario is a collection of executable steps of different type\n"),// f(TextStyle.DEFAULT, "\n"),// f(TextStyle.META_KEYWORD, "GivenStories: "),// f(TextStyle.META_DEFAULT, "path/to/precondition1.story,\n"),// f(TextStyle.META_DEFAULT, " path/to/precondition1.story,\n"),// f(TextStyle.DEFAULT, "\n"),// f(TextStyle.STEP_KEYWORD, "Given "),// f(TextStyle.STEP_DEFAULT, "a new user with the following properties:\n"),// f(TextStyle.STEP_EXAMPLE_TABLE_SEPARATOR,"|"),// f(TextStyle.STEP_EXAMPLE_TABLE_CELL,"firstname"),// f(TextStyle.STEP_EXAMPLE_TABLE_SEPARATOR,"|"),// f(TextStyle.STEP_EXAMPLE_TABLE_CELL,"Sherlock"),// f(TextStyle.STEP_EXAMPLE_TABLE_SEPARATOR,"|\n"),// f(TextStyle.STEP_EXAMPLE_TABLE_SEPARATOR,"|"),// f(TextStyle.STEP_EXAMPLE_TABLE_CELL,"lastname"),// f(TextStyle.STEP_EXAMPLE_TABLE_SEPARATOR,"|"),// f(TextStyle.STEP_EXAMPLE_TABLE_CELL,"Holmes"),// f(TextStyle.STEP_EXAMPLE_TABLE_SEPARATOR,"|\n"),// f(TextStyle.STEP_KEYWORD, "When "),// f(TextStyle.STEP_DEFAULT, "user clicks on "),// f(TextStyle.STEP_PARAMETER_VALUE, "login"),// f(TextStyle.STEP_DEFAULT, " button\n"),// f(TextStyle.STEP_KEYWORD, "And "),// f(TextStyle.STEP_DEFAULT, "user clicks on "),// f(TextStyle.STEP_PARAMETER, "$button_label"),// f(TextStyle.STEP_DEFAULT, " button\n"),// f(TextStyle.COMMENT, "!-- Look at this beautiful comment!\n"),// f(TextStyle.STEP_KEYWORD, "Then "),// f(TextStyle.STEP_DEFAULT, "login page must be displayed\n"),// f(TextStyle.DEFAULT, "\n"),// f(TextStyle.EXAMPLE_TABLE_KEYWORD, "ExampleTable:\n"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "user"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "login"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|\n"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "Sherlock Holmes"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "sherlock"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|\n"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "Arsene Lupin"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "arsene"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|\n"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "Fileas Fogg"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|"),// f(TextStyle.EXAMPLE_TABLE_CELL, "flogg"),// f(TextStyle.EXAMPLE_TABLE_SEPARATOR, "|\n") ); } private static Fragment f(String key, String content) { return new Fragment(key, content); } private static class Fragment { public String key; public String content; public Fragment(String key, String content) { super(); this.key = key; this.content = content; } } private void dumpCurrentStyle() { Map<String, TextStyle> map = rootStyle.createMap(); for(Map.Entry<String, TextStyle> e : map.entrySet()) { StringBuilder builder = new StringBuilder("define(map, "); builder.append('"').append(e.getKey()).append('"').append(", "); TextStyle style = e.getValue(); if(style.hasBackground()) { RGB rgb = style.getBackgroundOrDefault(); builder.append("new RGB(").append(rgb.red).append(",").append(rgb.green).append(",").append(rgb.blue).append(")"); } else builder.append("null"); builder.append(", "); if(style.hasForeground()) { RGB rgb = style.getForegroundOrDefault(); builder.append("new RGB(").append(rgb.red).append(",").append(rgb.green).append(",").append(rgb.blue).append(")"); } else builder.append("null"); builder.append(", "); builder.append(style.isItalic()).append(", ").append(style.isBold()).append(")"); System.out.println(builder); } } }