| /******************************************************************************* |
| * Copyright (c) 2004, 2015 Tasktop Technologies and others. |
| * 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: |
| * Tasktop Technologies - initial API and implementation |
| * Raphael Ackermann - spell checking support on bug 195514 |
| * Jingwen Ou - extensibility improvements |
| * David Green - fix for bug 256702 |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.tasks.ui.editors; |
| |
| import java.util.Iterator; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.ITextListener; |
| import org.eclipse.jface.text.TextEvent; |
| import org.eclipse.jface.text.source.AnnotationModel; |
| import org.eclipse.jface.text.source.IAnnotationAccess; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.text.source.SourceViewer; |
| import org.eclipse.mylyn.commons.ui.FillWidthLayout; |
| import org.eclipse.mylyn.commons.ui.compatibility.CommonThemes; |
| import org.eclipse.mylyn.commons.workbench.editors.CommonTextSupport; |
| import org.eclipse.mylyn.commons.workbench.forms.CommonFormUtil; |
| import org.eclipse.mylyn.internal.tasks.ui.commands.ViewSourceHandler; |
| import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTextViewerConfiguration.Mode; |
| import org.eclipse.mylyn.tasks.core.ITask; |
| import org.eclipse.mylyn.tasks.core.TaskRepository; |
| import org.eclipse.mylyn.tasks.ui.editors.AbstractRenderingEngine; |
| import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorExtension; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.StackLayout; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.FocusAdapter; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.FocusListener; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.contexts.IContextActivation; |
| import org.eclipse.ui.contexts.IContextService; |
| import org.eclipse.ui.editors.text.EditorsUI; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| import org.eclipse.ui.texteditor.AnnotationPreference; |
| import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; |
| import org.eclipse.ui.texteditor.MarkerAnnotationPreferences; |
| import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; |
| import org.eclipse.ui.themes.IThemeManager; |
| |
| /** |
| * A text attribute editor that can switch between a editor, preview and source view. |
| * |
| * @author Raphael Ackermann |
| * @author Steffen Pingel |
| * @author Jingwen Ou |
| */ |
| public class RichTextEditor { |
| |
| public enum State { |
| DEFAULT, BROWSER, EDITOR, PREVIEW; |
| }; |
| |
| public static class StateChangedEvent { |
| |
| public State state; |
| |
| } |
| |
| public interface StateChangedListener { |
| |
| public void stateChanged(StateChangedEvent event); |
| |
| } |
| |
| public class ViewSourceAction extends Action { |
| |
| public ViewSourceAction() { |
| super(Messages.RichTextAttributeEditor_Viewer_Source, SWT.TOGGLE); |
| setChecked(false); |
| setEnabled(false); |
| } |
| |
| @Override |
| public void run() { |
| if (isChecked()) { |
| showDefault(); |
| } else { |
| showEditor(); |
| } |
| if (editorLayout != null) { |
| EditorUtil.reflow(editorLayout.topControl); |
| } |
| ViewSourceHandler.setChecked(isChecked()); |
| } |
| |
| } |
| |
| private static final String KEY_TEXT_VERSION = "org.eclipse.mylyn.tasks.ui.textVersion"; //$NON-NLS-1$ |
| |
| private BrowserPreviewViewer browserViewer; |
| |
| private IContextActivation contextActivation; |
| |
| private final IContextService contextService; |
| |
| private Control control; |
| |
| private SourceViewer defaultViewer; |
| |
| private Composite editorComposite; |
| |
| private StackLayout editorLayout; |
| |
| private SourceViewer editorViewer; |
| |
| private final AbstractTaskEditorExtension extension; |
| |
| private Mode mode; |
| |
| private SourceViewer previewViewer; |
| |
| boolean readOnly; |
| |
| private AbstractRenderingEngine renderingEngine; |
| |
| private final TaskRepository repository; |
| |
| private boolean spellCheckingEnabled; |
| |
| private final int style; |
| |
| private FormToolkit toolkit; |
| |
| private final IAction viewSourceAction; |
| |
| private String text; |
| |
| /** |
| * Changed each time text is updated. |
| */ |
| private int textVersion; |
| |
| private final ListenerList stateChangedListeners = new ListenerList(ListenerList.IDENTITY); |
| |
| private final ITask task; |
| |
| @Deprecated |
| public RichTextEditor(TaskRepository repository, int style) { |
| this(repository, style, null, null, null); |
| } |
| |
| @Deprecated |
| public RichTextEditor(TaskRepository repository, int style, IContextService contextService, |
| AbstractTaskEditorExtension extension) { |
| this(repository, style, contextService, extension, null); |
| } |
| |
| public RichTextEditor(TaskRepository repository, int style, IContextService contextService, |
| AbstractTaskEditorExtension extension, ITask task) { |
| this.repository = repository; |
| this.style = style; |
| this.contextService = contextService; |
| this.extension = extension; |
| this.text = ""; //$NON-NLS-1$ |
| this.viewSourceAction = new ViewSourceAction(); |
| setMode(Mode.DEFAULT); |
| this.task = task; |
| } |
| |
| private SourceViewer configure(final SourceViewer viewer, Document document, boolean readOnly) { |
| // do this before setting the document to not require invalidating the presentation |
| installHyperlinkPresenter(viewer, repository, task, getMode()); |
| |
| updateDocument(viewer, document, readOnly); |
| if (readOnly) { |
| if (extension != null) { |
| // setting view source action |
| viewer.getControl().setData(ViewSourceHandler.VIEW_SOURCE_ACTION, viewSourceAction); |
| viewer.getControl().addFocusListener(new FocusAdapter() { |
| @Override |
| public void focusGained(FocusEvent e) { |
| ViewSourceHandler.setChecked(getViewer() == defaultViewer); |
| } |
| }); |
| } |
| } else { |
| installListeners(viewer); |
| viewer.getControl().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); |
| } |
| |
| // enable cut/copy/paste |
| CommonTextSupport.setTextViewer(viewer.getTextWidget(), viewer); |
| viewer.setEditable(!readOnly); |
| viewer.getTextWidget().setFont(getFont()); |
| if (toolkit != null) { |
| toolkit.adapt(viewer.getControl(), false, false); |
| } |
| EditorUtil.addScrollListener(viewer.getTextWidget()); |
| return viewer; |
| } |
| |
| /** Configures annotation model for spell checking. */ |
| private void updateDocument(SourceViewer viewer, Document document, boolean readOnly) { |
| if (new Integer(this.textVersion).equals(viewer.getData(KEY_TEXT_VERSION))) { |
| // already up-to-date, skip re-loading of the document |
| return; |
| } |
| |
| if (readOnly) { |
| viewer.setDocument(document); |
| } else { |
| AnnotationModel annotationModel = new AnnotationModel(); |
| viewer.showAnnotations(false); |
| viewer.showAnnotationsOverview(false); |
| IAnnotationAccess annotationAccess = new DefaultMarkerAnnotationAccess(); |
| final SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(viewer, null, |
| annotationAccess, EditorsUI.getSharedTextColors()); |
| Iterator<?> e = new MarkerAnnotationPreferences().getAnnotationPreferences().iterator(); |
| while (e.hasNext()) { |
| support.setAnnotationPreference((AnnotationPreference) e.next()); |
| } |
| support.install(EditorsUI.getPreferenceStore()); |
| viewer.getTextWidget().addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| support.uninstall(); |
| } |
| }); |
| //viewer.getTextWidget().setIndent(2); |
| viewer.setDocument(document, annotationModel); |
| } |
| viewer.setData(KEY_TEXT_VERSION, this.textVersion); |
| } |
| |
| public void createControl(Composite parent, FormToolkit toolkit) { |
| this.toolkit = toolkit; |
| |
| int style = this.style; |
| if (!isReadOnly() && (style & SWT.NO_SCROLL) == 0) { |
| style |= SWT.V_SCROLL; |
| } |
| |
| if (extension != null || renderingEngine != null) { |
| editorComposite = new Composite(parent, SWT.NULL); |
| editorLayout = new StackLayout() { |
| @Override |
| protected Point computeSize(Composite composite, int hint, int hint2, boolean flushCache) { |
| return topControl.computeSize(hint, hint2, flushCache); |
| } |
| }; |
| editorComposite.setLayout(editorLayout); |
| setControl(editorComposite); |
| |
| if (extension != null) { |
| if (isReadOnly()) { |
| editorViewer = extension.createViewer(repository, editorComposite, style, |
| createHyperlinkDetectorContext()); |
| } else { |
| editorViewer = extension.createEditor(repository, editorComposite, style, |
| createHyperlinkDetectorContext()); |
| editorViewer.getTextWidget().addFocusListener(new FocusListener() { |
| public void focusGained(FocusEvent e) { |
| setContext(); |
| } |
| |
| public void focusLost(FocusEvent e) { |
| unsetContext(); |
| } |
| }); |
| editorViewer.getTextWidget().addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| unsetContext(); |
| } |
| }); |
| } |
| configure(editorViewer, new Document(getText()), isReadOnly()); |
| show(editorViewer.getControl()); |
| } else { |
| defaultViewer = createDefaultEditor(editorComposite, style); |
| configure(defaultViewer, new Document(getText()), isReadOnly()); |
| show(defaultViewer.getControl()); |
| } |
| |
| if (!isReadOnly() && (style & SWT.NO_SCROLL) == 0) { |
| editorComposite.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); |
| } |
| |
| viewSourceAction.setEnabled(true); |
| } else { |
| defaultViewer = createDefaultEditor(parent, style); |
| configure(defaultViewer, new Document(getText()), isReadOnly()); |
| setControl(defaultViewer.getControl()); |
| |
| viewSourceAction.setEnabled(false); |
| } |
| } |
| |
| @SuppressWarnings({ "rawtypes" }) |
| private IAdaptable createHyperlinkDetectorContext() { |
| return new IAdaptable() { |
| public Object getAdapter(Class adapter) { |
| if (adapter == TaskRepository.class) { |
| return repository; |
| } |
| if (adapter == ITask.class) { |
| return task; |
| } |
| return null; |
| } |
| }; |
| } |
| |
| private SourceViewer createDefaultEditor(Composite parent, int styles) { |
| SourceViewer defaultEditor = new SourceViewer(parent, null, styles | SWT.WRAP); |
| |
| RepositoryTextViewerConfiguration viewerConfig = new RepositoryTextViewerConfiguration(repository, task, |
| isSpellCheckingEnabled() && !isReadOnly()); |
| viewerConfig.setMode(getMode()); |
| defaultEditor.configure(viewerConfig); |
| |
| return defaultEditor; |
| } |
| |
| private BrowserPreviewViewer getBrowserViewer() { |
| if (editorComposite == null || renderingEngine == null) { |
| return null; |
| } |
| |
| if (browserViewer == null) { |
| browserViewer = new BrowserPreviewViewer(getRepository(), renderingEngine); |
| browserViewer.createControl(editorComposite, toolkit); |
| } |
| return browserViewer; |
| } |
| |
| public Control getControl() { |
| return control; |
| } |
| |
| public SourceViewer getDefaultViewer() { |
| if (defaultViewer == null) { |
| defaultViewer = createDefaultEditor(editorComposite, style); |
| configure(defaultViewer, new Document(getText()), isReadOnly()); |
| |
| // fixed font size |
| defaultViewer.getTextWidget().setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT)); |
| // adapt maximize action |
| defaultViewer.getControl().setData(EditorUtil.KEY_TOGGLE_TO_MAXIMIZE_ACTION, |
| editorViewer.getControl().getData(EditorUtil.KEY_TOGGLE_TO_MAXIMIZE_ACTION)); |
| // adapt menu to the new viewer |
| installMenu(defaultViewer.getControl(), editorViewer.getControl().getMenu()); |
| } |
| return defaultViewer; |
| } |
| |
| public SourceViewer getEditorViewer() { |
| return editorViewer; |
| } |
| |
| private Font getFont() { |
| if (mode == Mode.DEFAULT) { |
| IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager(); |
| Font font = themeManager.getCurrentTheme().getFontRegistry().get(CommonThemes.FONT_EDITOR_COMMENT); |
| return font; |
| } else { |
| return EditorUtil.TEXT_FONT; |
| } |
| } |
| |
| public Mode getMode() { |
| return mode; |
| } |
| |
| /** |
| * @return The preview source viewer or null if there is no extension available or the attribute is read only |
| */ |
| private SourceViewer getPreviewViewer() { |
| if (extension == null) { |
| return null; |
| } |
| |
| // construct as needed |
| if (previewViewer == null) { |
| // previewer should always have a vertical scroll bar if it's editable |
| int previewViewerStyle = style; |
| if (getEditorViewer() != null) { |
| previewViewerStyle |= SWT.V_SCROLL; |
| } |
| previewViewer = extension.createViewer(repository, editorComposite, previewViewerStyle, |
| createHyperlinkDetectorContext()); |
| configure(previewViewer, new Document(getText()), true); |
| // adapt maximize action |
| previewViewer.getControl().setData(EditorUtil.KEY_TOGGLE_TO_MAXIMIZE_ACTION, |
| editorViewer.getControl().getData(EditorUtil.KEY_TOGGLE_TO_MAXIMIZE_ACTION)); |
| installMenu(previewViewer.getControl(), editorViewer.getControl().getMenu()); |
| //set the background color in case there is an incoming to show |
| previewViewer.getTextWidget().setBackground(editorComposite.getBackground()); |
| } |
| return previewViewer; |
| } |
| |
| public AbstractRenderingEngine getRenderingEngine() { |
| return renderingEngine; |
| } |
| |
| public TaskRepository getRepository() { |
| return repository; |
| } |
| |
| public String getText() { |
| return this.text; |
| } |
| |
| public SourceViewer getViewer() { |
| if (editorLayout == null) { |
| return defaultViewer; |
| } |
| if (defaultViewer != null && editorLayout.topControl == defaultViewer.getControl()) { |
| return defaultViewer; |
| } else if (previewViewer != null && editorLayout.topControl == previewViewer.getControl()) { |
| return previewViewer; |
| } else { |
| return editorViewer; |
| } |
| } |
| |
| public IAction getViewSourceAction() { |
| return viewSourceAction; |
| } |
| |
| public boolean hasBrowser() { |
| return renderingEngine != null; |
| } |
| |
| public boolean hasPreview() { |
| return extension != null && !isReadOnly(); |
| } |
| |
| public static RepositoryTextViewerConfiguration installHyperlinkPresenter(ISourceViewer viewer, |
| TaskRepository repository, ITask task, Mode mode) { |
| RepositoryTextViewerConfiguration configuration = new RepositoryTextViewerConfiguration(repository, task, false); |
| configuration.setMode(mode); |
| |
| // do not configure viewer, this has already been done in extension |
| |
| AbstractHyperlinkTextPresentationManager manager; |
| if (mode == Mode.DEFAULT) { |
| manager = new HighlightingHyperlinkTextPresentationManager(); |
| manager.setHyperlinkDetectors(configuration.getDefaultHyperlinkDetectors(viewer, null)); |
| manager.install(viewer); |
| |
| manager = new TaskHyperlinkTextPresentationManager(); |
| manager.setHyperlinkDetectors(configuration.getDefaultHyperlinkDetectors(viewer, Mode.TASK)); |
| manager.install(viewer); |
| } else if (mode == Mode.TASK_RELATION) { |
| manager = new TaskHyperlinkTextPresentationManager(); |
| manager.setHyperlinkDetectors(configuration.getDefaultHyperlinkDetectors(viewer, Mode.TASK_RELATION)); |
| manager.install(viewer); |
| } |
| |
| return configuration; |
| } |
| |
| private void installListeners(final SourceViewer viewer) { |
| viewer.addTextListener(new ITextListener() { |
| public void textChanged(TextEvent event) { |
| // filter out events caused by text presentation changes, e.g. annotation drawing |
| String value = viewer.getTextWidget().getText(); |
| if (!RichTextEditor.this.text.equals(value)) { |
| RichTextEditor.this.text = value; |
| RichTextEditor.this.textVersion++; |
| viewer.setData(KEY_TEXT_VERSION, RichTextEditor.this.textVersion); |
| valueChanged(value); |
| CommonFormUtil.ensureVisible(viewer.getTextWidget()); |
| } |
| } |
| }); |
| // ensure that tab traverses to next control instead of inserting a tab character unless editing multi-line text |
| if ((style & SWT.MULTI) != 0 && mode != Mode.DEFAULT) { |
| viewer.getTextWidget().addListener(SWT.Traverse, new Listener() { |
| public void handleEvent(Event event) { |
| switch (event.detail) { |
| case SWT.TRAVERSE_TAB_NEXT: |
| case SWT.TRAVERSE_TAB_PREVIOUS: |
| event.doit = true; |
| break; |
| } |
| } |
| }); |
| } |
| } |
| |
| private void installMenu(final Control control, Menu menu) { |
| if (menu != null) { |
| control.setMenu(menu); |
| control.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| control.setMenu(null); |
| } |
| }); |
| } |
| } |
| |
| public boolean isReadOnly() { |
| return readOnly; |
| } |
| |
| public boolean isSpellCheckingEnabled() { |
| return spellCheckingEnabled; |
| } |
| |
| private void setContext() { |
| if (contextService == null) { |
| return; |
| } |
| if (contextActivation != null) { |
| contextService.deactivateContext(contextActivation); |
| contextActivation = null; |
| } |
| if (contextService != null && extension.getEditorContextId() != null) { |
| contextActivation = contextService.activateContext(extension.getEditorContextId()); |
| } |
| } |
| |
| private void setControl(Control control) { |
| this.control = control; |
| } |
| |
| public void setMode(Mode mode) { |
| Assert.isNotNull(mode); |
| this.mode = mode; |
| } |
| |
| public void setReadOnly(boolean readOnly) { |
| this.readOnly = readOnly; |
| } |
| |
| public void setRenderingEngine(AbstractRenderingEngine renderingEngine) { |
| this.renderingEngine = renderingEngine; |
| } |
| |
| public void setSpellCheckingEnabled(boolean spellCheckingEnabled) { |
| this.spellCheckingEnabled = spellCheckingEnabled; |
| } |
| |
| public void setText(String value) { |
| this.text = value; |
| this.textVersion++; |
| SourceViewer viewer = getViewer(); |
| if (viewer != null) { |
| viewer.getDocument().set(value); |
| } |
| } |
| |
| /** |
| * Brings <code>control</code> to top. |
| */ |
| private void show(Control control) { |
| // no extension is available |
| if (editorComposite == null) { |
| return; |
| } |
| editorLayout.topControl = control; |
| if (editorComposite.getParent().getLayout() instanceof FillWidthLayout) { |
| ((FillWidthLayout) editorComposite.getParent().getLayout()).flush(); |
| } |
| editorComposite.layout(); |
| control.setFocus(); |
| fireStateChangedEvent(); |
| } |
| |
| protected void fireStateChangedEvent() { |
| if (stateChangedListeners.isEmpty()) { |
| return; |
| } |
| StateChangedEvent event = new StateChangedEvent(); |
| if (defaultViewer != null && defaultViewer.getControl() == editorLayout.topControl) { |
| event.state = State.DEFAULT; |
| } else if (editorViewer != null && editorViewer.getControl() == editorLayout.topControl) { |
| event.state = State.EDITOR; |
| } else if (previewViewer != null && previewViewer.getControl() == editorLayout.topControl) { |
| event.state = State.PREVIEW; |
| } else if (browserViewer != null && browserViewer.getControl() == editorLayout.topControl) { |
| event.state = State.BROWSER; |
| } |
| Object[] listeners = stateChangedListeners.getListeners(); |
| for (Object listener : listeners) { |
| ((StateChangedListener) listener).stateChanged(event); |
| } |
| } |
| |
| /** |
| * Brings <code>viewer</code> to top. |
| */ |
| private void show(SourceViewer viewer) { |
| // WikiText modifies the document therefore, set a new document every time a viewer is changed to synchronize content between viewers |
| // ensure that editor has an annotation model |
| updateDocument(viewer, new Document(getText()), !viewer.isEditable()); |
| show(viewer.getControl()); |
| } |
| |
| public void showBrowser() { |
| BrowserPreviewViewer viewer = getBrowserViewer(); |
| viewer.update(getText()); |
| if (viewer != null) { |
| show(viewer.getControl()); |
| } |
| } |
| |
| public void showDefault() { |
| show(getDefaultViewer()); |
| } |
| |
| public void showEditor() { |
| if (getEditorViewer() != null) { |
| show(getEditorViewer()); |
| } else { |
| show(getDefaultViewer()); |
| } |
| } |
| |
| private void showPreview(boolean sticky) { |
| if (!isReadOnly() && getPreviewViewer() != null) { |
| show(getPreviewViewer()); |
| } |
| } |
| |
| public void showPreview() { |
| showPreview(true); |
| } |
| |
| private void unsetContext() { |
| if (contextService == null) { |
| return; |
| } |
| if (contextActivation != null) { |
| contextService.deactivateContext(contextActivation); |
| contextActivation = null; |
| } |
| } |
| |
| protected void valueChanged(String value) { |
| } |
| |
| public void enableAutoTogglePreview() { |
| if (!isReadOnly() && getPreviewViewer() != null) { |
| final MouseAdapter listener = new MouseAdapter() { |
| private boolean toggled; |
| |
| @Override |
| public void mouseUp(MouseEvent e) { |
| if (!toggled && e.count == 1) { |
| // delay switching in case user intended to select text |
| Display.getDefault().timerExec(Display.getDefault().getDoubleClickTime(), new Runnable() { |
| |
| public void run() { |
| if (previewViewer.getTextWidget() == null || previewViewer.getTextWidget().isDisposed()) { |
| return; |
| } |
| |
| if (previewViewer.getTextWidget().getSelectionCount() == 0) { |
| int offset = previewViewer.getTextWidget().getCaretOffset(); |
| showEditor(); |
| editorViewer.getTextWidget().setCaretOffset(offset); |
| |
| // only do this once, let the user manage toggling from then on |
| toggled = true; |
| } |
| } |
| }); |
| } |
| } |
| }; |
| previewViewer.getTextWidget().addMouseListener(listener); |
| // editorViewer.getTextWidget().addFocusListener(new FocusAdapter() { |
| // @Override |
| // public void focusLost(FocusEvent e) { |
| // if (!previewSticky) { |
| // showPreview(false); |
| // } |
| // } |
| // }); |
| } |
| } |
| |
| /** |
| * Sets the background color for all instantiated viewers |
| * |
| * @param color |
| */ |
| public void setBackground(Color color) { |
| if (editorComposite != null && !editorComposite.isDisposed()) { |
| editorComposite.setBackground(color); |
| for (Control child : editorComposite.getChildren()) { |
| child.setBackground(color); |
| } |
| } |
| } |
| |
| public void addStateChangedListener(StateChangedListener listener) { |
| stateChangedListeners.add(listener); |
| } |
| |
| public void removeStateChangedListener(StateChangedListener listener) { |
| stateChangedListeners.remove(listener); |
| } |
| |
| } |