| //------------------------------------------------------------------------------ |
| // Copyright (c) 2005, 2007 IBM Corporation 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: |
| // IBM Corporation - initial implementation |
| //------------------------------------------------------------------------------ |
| package org.eclipse.epf.richtext; |
| |
| import java.io.File; |
| import java.io.StringWriter; |
| import java.io.UnsupportedEncodingException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.epf.common.html.HTMLFormatter; |
| import org.eclipse.epf.common.serviceability.Logger; |
| import org.eclipse.epf.common.utils.FileUtil; |
| import org.eclipse.epf.common.utils.XMLUtil; |
| import org.eclipse.epf.common.xml.XSLTProcessor; |
| import org.eclipse.epf.richtext.actions.CopyAction; |
| import org.eclipse.epf.richtext.actions.CutAction; |
| import org.eclipse.epf.richtext.actions.FindReplaceAction; |
| import org.eclipse.epf.richtext.actions.PasteAction; |
| import org.eclipse.epf.richtext.actions.PastePlainTextAction; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.browser.Browser; |
| import org.eclipse.swt.browser.LocationAdapter; |
| import org.eclipse.swt.browser.LocationEvent; |
| import org.eclipse.swt.browser.StatusTextEvent; |
| import org.eclipse.swt.browser.StatusTextListener; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.HelpListener; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.MenuEvent; |
| import org.eclipse.swt.events.MenuListener; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.layout.GridData; |
| 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.swt.widgets.MenuItem; |
| import org.eclipse.ui.PlatformUI; |
| |
| /** |
| * The default rich text control implementation. |
| * <p> |
| * The default rich text editor uses XHTML as the underlying markup language for |
| * the rich text content. It is implemented using a SWT <code>Browser</code> |
| * control and DHTML (HTML, CSS and JavaScript). |
| * |
| * @author Kelvin Low |
| * @author Jeff Hardy |
| * @since 1.0 |
| */ |
| public class RichText implements IRichText { |
| |
| // Encoded single quote. All single quotes need to be specially encoded to |
| // avoid JavaScript error when calling Browse.executeCommand(). |
| private static final String ENCODED_SINGLE_QUOTE = "%sq%"; //$NON-NLS-1$ |
| |
| private static final String ENCODED_NEWLINE = "%EOL%"; //$NON-NLS-1$ |
| |
| protected static final String STATUS_PREFIX = "$$$"; //$NON-NLS-1$ |
| |
| protected static final int STATUS_PREFIX_LENGTH = STATUS_PREFIX.length(); |
| |
| protected static final int STATUS_NOP = 0; |
| |
| protected static final int STATUS_INITIALIZED = 1; |
| |
| protected static final int STATUS_MODIFIED = 2; |
| |
| protected static final int STATUS_GET_TEXT = 3; |
| |
| protected static final int STATUS_KEY_DOWN = 4; |
| |
| protected static final int STATUS_KEY_UP = 5; |
| |
| protected static final int STATUS_SELECT_TEXT = 6; |
| |
| protected static final int STATUS_SELECT_CONTROL = 7; |
| |
| protected static final int STATUS_SELECT_NONE = 8; |
| |
| protected static final int STATUS_EXEC_CMD = 9; |
| |
| protected static final int STATUS_REFORMAT_LINKS = 10; |
| |
| // The default base path used for resolving links (<href>, <img>, etc.) |
| private static final String DEFAULT_BASE_PATH = System |
| .getProperty("user.home") //$NON-NLS-1$ |
| + System.getProperty("file.separator") + "rte"; //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| // If true, log debugging info. |
| protected boolean debug; |
| |
| // The plug-in logger. |
| protected Logger logger; |
| |
| // The underlying SWT Browser used for loading the JavaScript/DHTML editor. |
| protected Browser editor; |
| |
| // The underlying OleControlSite for the SWT Browser (Win32 only). |
| protected Control editorControl; |
| |
| // The base URL of the rich text control whose content was last |
| // copied to the clipboard. |
| protected static URL copyURL; |
| |
| // The context menu associated with this control. |
| protected Menu contextMenu; |
| |
| // The folder that contains the supporting CSS and JavaScript files |
| protected String rteFolder; |
| |
| // The URL that points to the supporting CSS and JavaScript files. |
| protected String rteURL; |
| |
| // The base path used for resolving links (<href>, <img>, etc.) |
| protected String basePath; |
| |
| // The DHTML initialization flag. |
| protected boolean initialized; |
| |
| // The initial focus. |
| protected boolean initializedWithFocus; |
| |
| // The control's initial text. This is used to cache the HTML source passed |
| // in via setText()while the DHTML initialization is happening. |
| protected String initialText; |
| |
| // The control's current text. |
| protected String currentText = ""; //$NON-NLS-1$ |
| |
| // The control's editable flag. |
| protected boolean editable = true; |
| |
| // The control's modification flag. |
| protected boolean modified; |
| |
| // The control's text and object selection flag. |
| protected boolean hasSelection; |
| |
| // The control's text selection |
| protected RichTextSelection richTextSelection = new RichTextSelection(); |
| |
| // JavaScript command execution status code. |
| protected int status = 0; |
| |
| // The HTML source formatter. |
| protected HTMLFormatter htmlFormatter; |
| |
| // The SWT event listeners. |
| protected Map<Listener, RichTextListener> listeners; |
| |
| // The modify listeners. |
| protected List<ModifyListener> modifyListeners; |
| |
| // The control's edit flag. |
| protected boolean notifyingModifyListeners = false; |
| |
| // The controls's focus flag. |
| protected boolean hasFocus = false; |
| |
| // The controls's processing JavaScript event flag. |
| protected boolean processingJSEvent = false; |
| |
| // The controls's processing MODIFIED JavaScript event flag. |
| protected boolean checkingModifyEvent = false; |
| |
| // The control's find/replace text action |
| protected FindReplaceAction findReplaceAction; |
| |
| // The control's IE flag |
| protected boolean isIE = false; |
| |
| /** |
| * Creates a new instance. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * the style for this control |
| * @param basePath |
| * the path used for resolving links |
| */ |
| public RichText(Composite parent, int style, String basePath) { |
| debug = RichTextPlugin.getDefault().isDebugging(); |
| logger = RichTextPlugin.getDefault().getLogger(); |
| findReplaceAction = new FindReplaceAction(this); |
| rteFolder = RichTextPlugin.getDefault().getInstallPath() + "rte/"; //$NON-NLS-1$ |
| rteURL = XMLUtil.escape("file://" + rteFolder); //$NON-NLS-1$ |
| setBasePath(basePath); |
| |
| try { |
| editor = new Browser(parent, SWT.NONE); |
| if (debug) { |
| printDebugMessage("RichText", "basePath=" + basePath); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| editor.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| editor.setData(PROPERTY_NAME, this); |
| init(parent, style); |
| } catch (Exception e) { |
| editor = null; |
| String msg = "Failed to create RichText with basePath=" + basePath; //$NON-NLS-1$ |
| logger.logError(msg, e); |
| if (debug) { |
| System.out.println(msg); |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| /** |
| * Creates a new instance. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * the style for this control |
| */ |
| public RichText(Composite parent, int style) { |
| this(parent, style, null); |
| } |
| |
| /** |
| * Sets the base path for resolving links. |
| */ |
| protected void setBasePath(String path) { |
| if (path != null && path.length() > 0) { |
| if (path.startsWith(FileUtil.UNC_PATH_PREFIX)) { |
| basePath = FileUtil.UNC_PATH_PREFIX |
| + FileUtil.appendSeparator(path.substring( |
| FileUtil.UNC_PATH_PREFIX_LENGTH).replace('\\', |
| '/'), "/"); //$NON-NLS-1$ |
| } else { |
| basePath = FileUtil.appendSeparator(path).replace('\\', '/'); |
| } |
| } else { |
| basePath = FileUtil.appendSeparator(DEFAULT_BASE_PATH).replace( |
| '\\', '/'); |
| } |
| } |
| |
| /** |
| * Initializes this control. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * the style for this control |
| * @throws Exception |
| * when an error has occurred while initialzing this control |
| */ |
| protected void init(Composite parent, int style) throws Exception { |
| try { |
| addStatusTextListener(); |
| if (debug) { |
| printDebugMessage("init", "added status text listener"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| String editorHTML = generateEditorHTML(); |
| if (debug) { |
| printDebugMessage("init", "generated editor HTML"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| editor.setText(editorHTML); |
| if (debug) { |
| printDebugMessage("init", "loaded editor HTML"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| contextMenu = new Menu(parent.getShell(), SWT.POP_UP); |
| editor.setMenu(contextMenu); |
| fillContextMenu(contextMenu); |
| if (debug) { |
| printDebugMessage("init", "added context menu"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| addListeners(); |
| if (debug) { |
| printDebugMessage("init", "added listeners"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| htmlFormatter = new HTMLFormatter(); |
| if (debug) { |
| printDebugMessage("init", "instantiated HTMLFormatter"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } catch (Exception e) { |
| editor = null; |
| dispose(); |
| throw e; |
| } |
| } |
| |
| /** |
| * Returns this rich text control. |
| * |
| * @return this rich text control |
| */ |
| public Control getControl() { |
| return editor; |
| } |
| |
| /** |
| * Sets the layout data. |
| * |
| * @param layoutData |
| * the layout data to set |
| */ |
| public void setLayoutData(Object layoutData) { |
| if (editor != null) { |
| editor.setLayoutData(layoutData); |
| } |
| } |
| |
| /** |
| * Returns the layout data. |
| * |
| * @return this control's layout data |
| */ |
| public Object getLayoutData() { |
| if (editor != null) { |
| return editor.getLayoutData(); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets focus to this control. |
| */ |
| public void setFocus() { |
| if (debug) { |
| printDebugMessage("setFocus, editable=" + editable); //$NON-NLS-1$ |
| } |
| if (editor != null) { |
| if (initialized) { |
| if (!editor.isFocusControl()) { |
| if (!Platform.getOS().equals("win32")) { //$NON-NLS-1$ |
| // Workaround for Mozilla and Firefox rich text editor focus |
| // issue. |
| editor.setFocus(); |
| } |
| executeCommand(RichTextCommand.SET_FOCUS); |
| } |
| hasFocus = true; |
| } else { |
| initializedWithFocus = true; |
| } |
| } |
| } |
| |
| /** |
| * Tells the control it does not have focus. |
| */ |
| public void setBlur() { |
| if (debug) { |
| printDebugMessage("setBlur, editable=" + editable); //$NON-NLS-1$ |
| } |
| if (editor != null) { |
| if (initialized) { |
| hasFocus = false; |
| } else { |
| initializedWithFocus = false; |
| } |
| } |
| } |
| |
| /** |
| * Checks whether this control has focus. |
| * |
| * @return <code>true</code> if this control has the user-interface focus |
| */ |
| public boolean hasFocus() { |
| if (editor != null) { |
| return hasFocus; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the base path used for resolving text and image links. |
| * |
| * @return the base path used for resolving links in this control |
| */ |
| public String getBasePath() { |
| return basePath; |
| } |
| |
| /** |
| * Returns the base URL of the rich text control whose content was last |
| * copied to the clipboard. |
| * |
| * @return the base URL of a rich text control |
| */ |
| public URL getCopyURL() { |
| return copyURL; |
| } |
| |
| /** |
| * Sets the base URL of the rich text control whose content was last copied |
| * to the clipboard. |
| */ |
| public void setCopyURL() { |
| try { |
| copyURL = new File(basePath).toURL(); |
| } catch (Exception e) { |
| copyURL = null; |
| } |
| } |
| |
| /** |
| * Returns the editable state. |
| * |
| * @return <code>true</code> if the content is editable |
| */ |
| public boolean getEditable() { |
| return editable; |
| } |
| |
| /** |
| * Sets the editable state. |
| * |
| * @param editable |
| * the editable state |
| */ |
| public void setEditable(boolean editable) { |
| this.editable = editable; |
| if (initialized) { |
| executeCommand(RichTextCommand.SET_EDITABLE, "" + editable); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Checks whether the content has been modified. |
| * |
| * @return <code>true</code> if the content has been modified |
| */ |
| public boolean getModified() { |
| return modified; |
| } |
| |
| /** |
| * Sets the modified state. |
| * |
| * @param modified |
| * the modified state |
| */ |
| public void setModified(boolean modified) { |
| this.modified = modified; |
| } |
| |
| /** |
| * Returns the rich text content. |
| * |
| * @return the rich text content formatted in a markup language |
| */ |
| public String getText() { |
| if (editor != null && initialized) { |
| try { |
| executeCommand(RichTextCommand.GET_TEXT); |
| if (currentText != null && currentText.length() > 0) { |
| currentText = currentText.replaceAll( |
| "<P> </P>", "<br/>"); //$NON-NLS-1$ //$NON-NLS-2$ |
| currentText = tidyText(currentText); |
| currentText = formatHTML(currentText); |
| } else { |
| currentText = ""; //$NON-NLS-1$ |
| } |
| if (debug) { |
| printDebugMessage("getText", "text=", currentText); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| return currentText; |
| } catch (Exception e) { |
| logger.logError(e); |
| } |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| protected String formatHTML(String text) { |
| String formattedText; |
| try { |
| // Call JTidy to format the source to XHTML. |
| formattedText = htmlFormatter.formatHTML(text); |
| if (htmlFormatter.getLastErrorStr() != null) { |
| logger.logError(htmlFormatter.getLastErrorStr()); |
| } |
| return formattedText; |
| } catch (UnsupportedEncodingException e) { |
| logger.logError(e); |
| } |
| return text; |
| } |
| |
| /** |
| * Sets the rich text content. |
| * |
| * @param text |
| * the rich text content formatted in a markup language |
| */ |
| public void setText(String text) { |
| if (editor != null) { |
| if (debug) { |
| printDebugMessage("setText", "text=", text); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| String newText = text; |
| if (newText != null) { |
| newText = tidyText(newText); |
| // Call JTidy to format the source to XHTML. |
| newText = formatHTML(newText); |
| } else { |
| newText = ""; //$NON-NLS-1$ |
| } |
| |
| if (initialized) { |
| modified = !newText.equals(currentText); |
| } |
| initialText = newText; |
| if (initialText.equals("") && !isIE) { //$NON-NLS-1$ |
| initialText = "<br />"; //$NON-NLS-1$ |
| } |
| |
| if (debug) { |
| printDebugMessage( |
| "setText", "modified=" + modified + ", newText=", newText); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| if (initialized) { |
| try { |
| executeCommand(RichTextCommand.SET_TEXT, newText); |
| executeCommand(RichTextCommand.SET_EDITABLE, "" + editable); //$NON-NLS-1$ |
| } catch (Exception e) { |
| logger.logError(e); |
| } |
| } |
| |
| currentText = newText; |
| } |
| } |
| |
| /** |
| * Restores the rich text content back to the initial value. |
| */ |
| public void restoreText() { |
| setText(initialText); |
| modified = false; |
| } |
| |
| /** |
| * Returns the currently selected text. |
| * |
| * @return the selected text or <code>""</code> if there is no |
| * hasSelection |
| */ |
| public String getSelectedText() { |
| // executeCommand(RichTextCommand.GET_SELECTED_TEXT); |
| return richTextSelection.getText(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.richtext.IRichText#getSelected() |
| */ |
| public RichTextSelection getSelected() { |
| return richTextSelection; |
| } |
| |
| /** |
| * Returns an application specific property value. |
| * |
| * @param key |
| * the name of the property |
| * @return the value of the property or <code>null</code> if it has not |
| * been set |
| */ |
| public Object getData(String key) { |
| if (editor != null) { |
| editor.getData(key); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets an application specific property name and value. |
| * |
| * @param key |
| * the name of the property |
| * @param value |
| * the property value |
| */ |
| public void setData(String key, Object value) { |
| if (editor != null) { |
| editor.setData(key, value); |
| } |
| } |
| |
| /** |
| * Executes the given JavaScript. |
| * |
| * @param script |
| * the JavaScript to execute |
| * @return a status code returned by the executed script |
| */ |
| protected int execute(final String script) { |
| status = 0; |
| if (editor != null && script != null && script.length() > 0) { |
| try { |
| if (!isIE && processingJSEvent) { |
| Display.getCurrent().asyncExec(new Runnable() { |
| public void run() { |
| if (!isDisposed()) { |
| editor.execute(script); |
| } |
| } |
| }); |
| } else { |
| editor.execute(script); |
| } |
| if (debug) { |
| printDebugMessage("execute", script); //$NON-NLS-1$ |
| } |
| } catch (Exception e) { |
| String msg = "Failed to execute " + script; //$NON-NLS-1$ |
| logger.logError(msg, e); |
| if (debug) { |
| printDebugMessage("execute", msg); //$NON-NLS-1$ |
| e.printStackTrace(); |
| } |
| } |
| } |
| return status; |
| } |
| |
| /** |
| * Executes the given rich text command. The supported command strings are |
| * defined in <code>RichTextCommand<code>. |
| * |
| * @param command a rich text command string. |
| * @return a status code returned by the executed command |
| */ |
| public int executeCommand(String command) { |
| status = 0; |
| if (command != null && command.equals(RichTextCommand.CLEAR_CONTENT)) { |
| String oldInitialText = initialText; |
| setText(""); //$NON-NLS-1$ |
| initialText = oldInitialText; |
| status = 1; |
| modified = true; |
| notifyModifyListeners(); |
| } else { |
| status = execute(command + "();"); //$NON-NLS-1$ |
| } |
| return status; |
| } |
| |
| /** |
| * Executes the given rich text command with a single parameter. The |
| * supported command strings are defined in <code>RichTextCommand<code>. |
| * |
| * @param command a rich text command string |
| * @param param a parameter for the command or <code>null</code> |
| * @return a status code returned by the executed command |
| */ |
| public int executeCommand(String command, String param) { |
| if (param == null) { |
| return executeCommand(command); |
| } |
| return execute(command + "('" + formatText(param) + "');"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Executes the given rich text command with an array of parameters. The |
| * supported command strings are defined in <code>RichTextCommand<code>. |
| * |
| * @param command a rich text command string |
| * @param params an array of parameters for the command or <code>null</code> |
| * @return a status code returned by the executed command |
| */ |
| public int executeCommand(String command, String[] params) { |
| if (params == null || params.length == 0) { |
| return executeCommand(command); |
| } |
| StringBuffer sb = new StringBuffer(); |
| int paramsLength = params.length; |
| for (int i = 0; i < paramsLength; i++) { |
| sb.append('\'').append(formatText(params[i])).append('\''); |
| if (i < paramsLength - 1) { |
| sb.append(','); |
| } |
| } |
| String param = sb.toString(); |
| return execute(command + "(" + param + ");"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Disposes the operating system resources allocated by the control. |
| */ |
| public void dispose() { |
| if (contextMenu != null && !contextMenu.isDisposed()) { |
| contextMenu.dispose(); |
| contextMenu = null; |
| } |
| if (listeners != null) { |
| listeners.clear(); |
| listeners = null; |
| } |
| if (modifyListeners != null) { |
| modifyListeners.clear(); |
| modifyListeners = null; |
| } |
| if (htmlFormatter != null) { |
| htmlFormatter = null; |
| } |
| if (this.findReplaceAction != null) { |
| this.findReplaceAction.dispose(); |
| this.findReplaceAction = null; |
| } |
| } |
| |
| /** |
| * Checks whether this control has been disposed. |
| * |
| * @return <code>true</code> if this control is disposed successfully |
| */ |
| public boolean isDisposed() { |
| return editor.isDisposed(); |
| } |
| |
| /** |
| * Returns the modify listeners attached to this control. |
| * |
| * @return an iterator for retrieving the modify listeners |
| */ |
| public Iterator<ModifyListener> getModifyListeners() { |
| return modifyListeners.iterator(); |
| } |
| |
| /** |
| * Adds a listener to the collection of listeners who will be notified when |
| * keys are pressed and released within this control. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addKeyListener(KeyListener listener) { |
| if (editor != null) { |
| editor.addKeyListener(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when keys are pressed and released within this control. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeKeyListener(KeyListener listener) { |
| if (editor != null) { |
| editor.removeKeyListener(listener); |
| } |
| } |
| |
| /** |
| * Adds a listener to the collection of listeners who will be notified when |
| * the content of this control is modified. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addModifyListener(ModifyListener listener) { |
| if (editor != null && listener != null |
| && !modifyListeners.contains(listener)) { |
| modifyListeners.add(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when the content of this control is modified. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeModifyListener(ModifyListener listener) { |
| if (editor != null && listener != null |
| && modifyListeners.contains(listener)) { |
| modifyListeners.remove(listener); |
| } |
| } |
| |
| /** |
| * Adds the listener to the collection of listeners who will be notifed when |
| * this control is disposed. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addDisposeListener(DisposeListener listener) { |
| if (editor != null) { |
| editor.addDisposeListener(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when this control is disposed. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeDisposeListener(DisposeListener listener) { |
| if (editor != null) { |
| editor.removeDisposeListener(listener); |
| } |
| } |
| |
| /** |
| * Adds a listener to the collection of listeners who will be notified when |
| * help events are generated for this control. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addHelpListener(HelpListener listener) { |
| if (editor != null) { |
| editor.addHelpListener(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when help events are generated for this control. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeHelpListener(HelpListener listener) { |
| if (editor != null) { |
| editor.removeHelpListener(listener); |
| } |
| } |
| |
| /** |
| * Adds the listener to the collection of listeners who will be notifed when |
| * an event of the given type occurs within this control. |
| * |
| * @param eventType |
| * the type of event to listen for |
| * @param listener |
| * the listener which should be notified when the event occurs |
| */ |
| public void addListener(int eventType, Listener listener) { |
| if (editor != null && !listeners.containsKey(listener)) { |
| if (eventType != SWT.SELECTED) { |
| if (editorControl == null |
| || (eventType != SWT.Activate |
| && eventType != SWT.Deactivate |
| && eventType != SWT.FocusIn && eventType != SWT.FocusOut)) { |
| editor.addListener(eventType, listener); |
| } |
| } |
| listeners.put(listener, new RichTextListener(eventType, listener)); |
| } |
| } |
| |
| /** |
| * Removes the listener from the collection of listeners who will be notifed |
| * when an event of the given type occurs within this control. |
| * |
| * @param eventType |
| * the type of event to listen for |
| * @param listener |
| * the listener which should no longer be notified when the event |
| * occurs |
| */ |
| public void removeListener(int eventType, Listener listener) { |
| if (editor != null && listeners.containsKey(listener)) { |
| if (editorControl == null |
| || (eventType != SWT.Activate |
| && eventType != SWT.Deactivate |
| && eventType != SWT.FocusIn && eventType != SWT.FocusOut)) { |
| editor.removeListener(eventType, listener); |
| } |
| listeners.remove(listener); |
| } |
| } |
| |
| /** |
| * Returns the event listeners attached to this control. |
| * |
| * @return an iterator for retrieving the event listeners attached to this |
| * control |
| */ |
| public Iterator<RichTextListener> getListeners() { |
| return listeners.values().iterator(); |
| } |
| |
| /** |
| * Adds the listener to monitor events and status sent by the underlying |
| * DHTML editor. |
| */ |
| protected void addStatusTextListener() { |
| editor.addStatusTextListener(new StatusTextListener() { |
| public void changed(StatusTextEvent event) { |
| String eventText = event.text; |
| int eventTextLength = eventText.length(); |
| if (eventText.startsWith(STATUS_PREFIX) |
| && eventTextLength > STATUS_PREFIX_LENGTH) { |
| try { |
| processingJSEvent = true; |
| int endStatusIndex = STATUS_PREFIX_LENGTH + 1; |
| if (eventText.length() > STATUS_PREFIX_LENGTH + 1 |
| && Character.isDigit(eventText |
| .charAt(endStatusIndex))) { |
| endStatusIndex++; |
| } |
| int statusType = Integer.parseInt(eventText.substring( |
| STATUS_PREFIX_LENGTH, endStatusIndex)); |
| switch (statusType) { |
| case STATUS_NOP: |
| break; |
| case STATUS_INITIALIZED: |
| if (!initialized) { |
| initialized = true; |
| if (debug) { |
| printDebugMessage( |
| "statusTextListener", "STATUS_INITIALIZED"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| if (!Platform.getOS().equals("win32")) { //$NON-NLS-1$ |
| // Workaround Mozilla'a IFRAME |
| // height issue. |
| executeCommand(RichTextCommand.SET_HEIGHT, |
| "" + editor.getBounds().height); //$NON-NLS-1$ |
| } |
| executeCommand(RichTextCommand.SET_TEXT, |
| currentText); |
| if (initializedWithFocus) { |
| setFocus(); |
| } |
| if (!editable) { |
| executeCommand( |
| RichTextCommand.SET_EDITABLE, |
| "" + editable); //$NON-NLS-1$ |
| } |
| } |
| break; |
| case STATUS_MODIFIED: |
| if (debug) { |
| printDebugMessage( |
| "statusTextListener", "STATUS_MODIFIED"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| checkModify(); |
| break; |
| case STATUS_GET_TEXT: |
| if (eventTextLength >= STATUS_PREFIX_LENGTH + 2) { |
| currentText = eventText |
| .substring(STATUS_PREFIX_LENGTH + 2); |
| } else { |
| currentText = ""; //$NON-NLS-1$ |
| } |
| if (debug) { |
| printDebugMessage( |
| "statusTextListener", //$NON-NLS-1$ |
| "STATUS_GET_TEXT, currentText=", currentText); //$NON-NLS-1$ |
| } |
| break; |
| case STATUS_KEY_DOWN: |
| if (eventTextLength >= STATUS_PREFIX_LENGTH + 2) { |
| String cmd = eventText |
| .substring(STATUS_PREFIX_LENGTH + 2); |
| if (debug) { |
| printDebugMessage("statusTextListener", //$NON-NLS-1$ |
| "STATUS_KEY_DOWN, cmd=" + cmd); //$NON-NLS-1$ |
| } |
| if (cmd.equals(RichTextCommand.COPY)) { |
| setCopyURL(); |
| } else if (cmd.equals(RichTextCommand.CUT)) { |
| setCopyURL(); |
| CutAction action = new CutAction( |
| RichText.this); |
| action.execute(RichText.this); |
| } else if (cmd |
| .equals(RichTextCommand.FIND_TEXT)) { |
| getFindReplaceAction().execute( |
| RichText.this); |
| } else if (cmd.equals(RichTextCommand.PASTE)) { |
| PasteAction action = new PasteAction( |
| RichText.this); |
| action.execute(RichText.this); |
| } else if (cmd.equals(RichTextCommand.SAVE)) { |
| PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow() |
| .getActivePage().getActiveEditor() |
| .doSave(null); |
| } else if (cmd.equals(RichTextCommand.SAVE_ALL)) { |
| PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow() |
| .getActivePage().saveAllEditors( |
| false); |
| } |
| } |
| break; |
| case STATUS_KEY_UP: |
| if (debug) { |
| printDebugMessage("statusTextListener", //$NON-NLS-1$ |
| "STATUS_KEY_UP, modified=" + modified); //$NON-NLS-1$ |
| } |
| checkModify(); |
| break; |
| case STATUS_SELECT_TEXT: |
| if (eventTextLength >= STATUS_PREFIX_LENGTH + 2) { |
| String[] strings = eventText.substring( |
| STATUS_PREFIX_LENGTH + 2).split( |
| "\\$", 5); //$NON-NLS-1$ |
| try { |
| richTextSelection.setFontName(strings[0]); |
| richTextSelection.setFontSize(strings[1]); |
| richTextSelection.setBlockStyle(strings[2]); |
| richTextSelection.setFlags(Integer |
| .parseInt(strings[3])); |
| richTextSelection.setText(strings[4]); |
| } catch (NumberFormatException e) { |
| logger.logError(e); |
| } |
| if (debug) { |
| printDebugMessage( |
| "selectionStatusListener", //$NON-NLS-1$ |
| "current selection is=" + richTextSelection); //$NON-NLS-1$ |
| } |
| |
| hasSelection = true; |
| if (hasFocus()) |
| notifyListeners(SWT.SELECTED, new Event()); |
| } else { |
| richTextSelection.setText(""); //$NON-NLS-1$ |
| hasSelection = false; |
| } |
| if (debug) { |
| printDebugMessage( |
| "statusTextListener", //$NON-NLS-1$ |
| "STATUS_SELECT_TEXT, selectedText=", richTextSelection.getText()); //$NON-NLS-1$ |
| } |
| break; |
| case STATUS_SELECT_CONTROL: |
| if (debug) { |
| printDebugMessage("statusTextListener", //$NON-NLS-1$ |
| "STATUS_SELECT_CONTROL, control selected"); //$NON-NLS-1$ |
| } |
| hasSelection = true; |
| break; |
| case STATUS_SELECT_NONE: |
| if (debug) { |
| printDebugMessage("statusTextListener", //$NON-NLS-1$ |
| "STATUS_SELECT_NONE, no selection"); //$NON-NLS-1$ |
| } |
| hasSelection = false; |
| break; |
| case STATUS_EXEC_CMD: |
| if (eventTextLength >= STATUS_PREFIX_LENGTH + 3) { |
| try { |
| status = Integer.parseInt(eventText |
| .substring( |
| STATUS_PREFIX_LENGTH + 2, |
| STATUS_PREFIX_LENGTH + 3)); |
| } catch (Exception e) { |
| status = -1; |
| } |
| } |
| if (debug && status != 1) { |
| printDebugMessage("statusTextListener", //$NON-NLS-1$ |
| "STATUS_EXEC_CMD, status=" + status); //$NON-NLS-1$ |
| } |
| break; |
| case STATUS_REFORMAT_LINKS: |
| if (debug) { |
| printDebugMessage( |
| "statusTextListener", "STATUS_REFORMAT_LINKS"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| if (Platform.getOS().equals("win32")) { //$NON-NLS-1$ |
| // Workaround the drag and drop issue with DBCS |
| // characters. |
| if (modified) { |
| setText(getText()); |
| modified = true; |
| } |
| } |
| checkModify(); |
| break; |
| } |
| } catch (Exception e) { |
| } finally { |
| processingJSEvent = false; |
| } |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Generates the HTML source for the editor. |
| * |
| * @return the HTML source for the editor |
| */ |
| protected String generateEditorHTML() throws Exception { |
| String escapedBasePath = basePath; |
| if (escapedBasePath.startsWith(FileUtil.UNC_PATH_PREFIX)) |
| escapedBasePath = escapedBasePath.replaceFirst( |
| "^\\\\\\\\", "\\\\\\\\\\\\\\\\"); //$NON-NLS-1$ //$NON-NLS-2$ |
| escapedBasePath = XMLUtil |
| .escape("file://" + escapedBasePath.replaceAll("'", "\\\\'")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| String escapedRteUTL = rteURL.replaceAll("'", "%27"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| StringBuffer rteXML = new StringBuffer(); |
| rteXML.append("<rte id=\"").append("rte") //$NON-NLS-1$ //$NON-NLS-2$ |
| .append("\" css=\"").append(escapedRteUTL + "rte.css") //$NON-NLS-1$ //$NON-NLS-2$ |
| .append("\" js=\"").append(escapedRteUTL + "rte.js") //$NON-NLS-1$ //$NON-NLS-2$ |
| .append("\" baseURL=\"").append(escapedBasePath) //$NON-NLS-1$ |
| .append("\"/>"); //$NON-NLS-1$ |
| StringWriter result = new StringWriter(); |
| XSLTProcessor.transform( |
| rteFolder + "rte.xsl", rteXML.toString(), result); //$NON-NLS-1$ |
| return result.toString(); |
| } |
| |
| /** |
| * Fills the context menu with menu items. |
| * |
| * @param contextMenu |
| * a context menu containing rich text actions |
| */ |
| protected void fillContextMenu(Menu contextMenu) { |
| final MenuItem cutItem = new MenuItem(contextMenu, SWT.PUSH); |
| cutItem.setText(RichTextResources.cutAction_text); |
| cutItem.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| CutAction action = new CutAction(RichText.this); |
| action.execute(RichText.this); |
| } |
| }); |
| final MenuItem copyItem = new MenuItem(contextMenu, SWT.PUSH); |
| copyItem.setText(RichTextResources.copyAction_text); |
| copyItem.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| CopyAction action = new CopyAction(RichText.this); |
| action.execute(RichText.this); |
| } |
| }); |
| final MenuItem pasteItem = new MenuItem(contextMenu, SWT.PUSH); |
| pasteItem.setText(RichTextResources.pasteAction_text); |
| pasteItem.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| PasteAction action = new PasteAction(RichText.this); |
| action.execute(RichText.this); |
| } |
| }); |
| |
| final MenuItem pastePlainTextItem = new MenuItem(contextMenu, SWT.PUSH); |
| pastePlainTextItem.setText(RichTextResources.pastePlainTextAction_text); |
| pastePlainTextItem.setImage(RichTextImages.IMG_PASTE_PLAIN_TEXT); |
| pastePlainTextItem.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| PastePlainTextAction action = new PastePlainTextAction( |
| RichText.this); |
| action.execute(RichText.this); |
| } |
| }); |
| |
| contextMenu.addMenuListener(new MenuListener() { |
| public void menuHidden(MenuEvent e) { |
| } |
| |
| public void menuShown(MenuEvent e) { |
| getSelectedText(); |
| cutItem.setEnabled(editable && hasSelection); |
| copyItem.setEnabled(hasSelection); |
| pasteItem.setEnabled(editable); |
| pastePlainTextItem.setEnabled(editable); |
| } |
| }); |
| } |
| |
| /** |
| * Adds listeners to manage the activation and focus events. |
| */ |
| protected void addListeners() { |
| editorControl = getControlSite(editor); |
| if (editorControl != null) { |
| if (debug) { |
| printDebugMessage( |
| "init", "editorControl=" + editorControl.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| // only IE (win32) has the editorControl != null |
| isIE = true; |
| |
| editorControl.addListener(SWT.Activate, new Listener() { |
| public void handleEvent(Event event) { |
| if (debug) { |
| printDebugMessage("activateListener"); //$NON-NLS-1$ |
| } |
| setFocus(); |
| notifyListeners(SWT.Activate, event); |
| } |
| }); |
| |
| editorControl.addListener(SWT.Deactivate, new Listener() { |
| public void handleEvent(Event event) { |
| if (debug) { |
| printDebugMessage("deactivateListener"); //$NON-NLS-1$ |
| } |
| setBlur(); |
| notifyListeners(SWT.Deactivate, event); |
| } |
| }); |
| |
| editorControl.addListener(SWT.FocusIn, new Listener() { |
| public void handleEvent(Event event) { |
| if (debug) { |
| printDebugMessage("focusInListener"); //$NON-NLS-1$ |
| } |
| executeCommand("updateSelection"); //$NON-NLS-1$ |
| notifyListeners(SWT.FocusIn, event); |
| } |
| }); |
| |
| editorControl.addListener(SWT.KeyUp, new Listener() { |
| public void handleEvent(Event event) { |
| int keyCode = event.keyCode; |
| int stateMask = event.stateMask; |
| if (debug) { |
| printDebugMessage( |
| "keyUpListener", "keyCode=" + keyCode //$NON-NLS-1$ //$NON-NLS-2$ |
| + ", stateMask=" + stateMask + ", editable=" + editable); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| if ((stateMask & SWT.CTRL) > 0 |
| || (stateMask & SWT.ALT) > 0 |
| || ((stateMask & SWT.SHIFT) > 0 && keyCode == stateMask)) { |
| return; |
| } |
| if (editable) { |
| switch (event.keyCode) { |
| case SWT.ARROW_DOWN: |
| case SWT.ARROW_LEFT: |
| case SWT.ARROW_RIGHT: |
| case SWT.ARROW_UP: |
| case SWT.END: |
| case SWT.HOME: |
| case SWT.PAGE_DOWN: |
| case SWT.PAGE_UP: |
| case SWT.TAB: |
| return; |
| default: |
| checkModify(); |
| break; |
| } |
| } |
| } |
| }); |
| |
| editor.addLocationListener(new LocationAdapter() { |
| public void changing(LocationEvent event) { |
| // Deactivate the links in the content page in readonly |
| // mode. |
| event.doit = editable; |
| } |
| }); |
| } else { |
| editor.addListener(SWT.Activate, new Listener() { |
| public void handleEvent(Event event) { |
| if (debug) { |
| printDebugMessage("activateListener"); //$NON-NLS-1$ |
| } |
| setFocus(); |
| } |
| }); |
| |
| editor.addKeyListener(new KeyListener() { |
| public void keyPressed(KeyEvent e) { |
| if (e.keyCode == SWT.TAB) { |
| if ((e.stateMask & SWT.SHIFT) != 0) { |
| editor.traverse(SWT.TRAVERSE_TAB_PREVIOUS); |
| } else { |
| editor.traverse(SWT.TRAVERSE_TAB_NEXT); |
| } |
| return; |
| } |
| if (!editable) { |
| e.doit = false; |
| } |
| } |
| |
| public void keyReleased(KeyEvent e) { |
| if ((e.stateMask & SWT.CTRL) > 0 |
| || (e.stateMask & SWT.ALT) > 0) |
| return; |
| if (editable) { |
| switch (e.keyCode) { |
| case SWT.ARROW_DOWN: |
| case SWT.ARROW_LEFT: |
| case SWT.ARROW_RIGHT: |
| case SWT.ARROW_UP: |
| case SWT.END: |
| case SWT.HOME: |
| case SWT.PAGE_DOWN: |
| case SWT.PAGE_UP: |
| case SWT.SHIFT: |
| case SWT.TAB: |
| break; |
| default: |
| checkModify(); |
| break; |
| } |
| } |
| } |
| }); |
| } |
| |
| editor.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| if (debug) { |
| printDebugMessage("disposeListener"); //$NON-NLS-1$ |
| } |
| dispose(); |
| } |
| }); |
| |
| listeners = new Hashtable<Listener, RichTextListener>(); |
| modifyListeners = new ArrayList<ModifyListener>(); |
| } |
| |
| /** |
| * Notifies the rich text event listeners. |
| * |
| * @param eventType |
| * the event type |
| * @param event |
| * the SWT event |
| */ |
| protected void notifyListeners(int eventType, Event event) { |
| if (notifyingModifyListeners) { |
| return; |
| } |
| |
| if (listeners != null) { |
| event.display = Display.getCurrent(); |
| event.widget = editor; |
| |
| for (Iterator<RichTextListener> i = listeners.values().iterator(); i |
| .hasNext();) { |
| RichTextListener listener = i.next(); |
| if (listener.getEventType() == eventType) { |
| if (debug) { |
| printDebugMessage( |
| "notifyListeners", "notifying listener, " + listener + ", eventType=" + eventType); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| listener.getListener().handleEvent(event); |
| if (debug) { |
| printDebugMessage( |
| "notifyListeners", "notified listener, " + listener + ", eventType=" + eventType); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Notifies the modify listeners that the rich text editor content has |
| * changed. |
| */ |
| public void notifyModifyListeners() { |
| notifyingModifyListeners = true; |
| |
| Event event = new Event(); |
| event.display = Display.getCurrent(); |
| event.widget = editor; |
| |
| for (Iterator<ModifyListener> i = modifyListeners.iterator(); i |
| .hasNext();) { |
| ModifyListener listener = i.next(); |
| if (debug) { |
| printDebugMessage( |
| "notifyModifyListeners", "notifying listener, " + listener); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| listener.modifyText(new ModifyEvent(event)); |
| if (debug) { |
| printDebugMessage( |
| "notifyModifyListeners", "notified listener, " + listener); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| |
| notifyingModifyListeners = false; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.richtext.IRichText#checkModify() |
| */ |
| public void checkModify() { |
| try { |
| if (!checkingModifyEvent) { |
| checkingModifyEvent = true; |
| if (modified) { |
| notifyModifyListeners(); |
| } else { |
| if (!isIE && processingJSEvent) { |
| Display.getCurrent().asyncExec(new Runnable() { |
| public void run() { |
| if (!getText().equals(initialText)) { |
| modified = true; |
| notifyModifyListeners(); |
| } |
| } |
| }); |
| } else { |
| if (!getText().equals(initialText)) { |
| modified = true; |
| notifyModifyListeners(); |
| } |
| } |
| } |
| if (debug) { |
| printDebugMessage("checkModify", "modified=" + modified); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } finally { |
| checkingModifyEvent = false; |
| } |
| } |
| |
| /** |
| * This provides an opportunity for a sub class to tidy up the rich text. |
| * |
| * @param text |
| * rich text encoded in HTML format |
| */ |
| protected String tidyText(String text) { |
| return text; |
| } |
| |
| /** |
| * Formats the text for consumption by the JavaScript/DHTML editor. |
| * |
| * @param text |
| * rich text encoded in HTML format |
| */ |
| protected String formatText(String text) { |
| if (text == null || text.length() == 0) { |
| return text; |
| } |
| StringBuffer result = new StringBuffer(); |
| int textSize = text.length(); |
| for (int i = 0; i < textSize; i++) { |
| char ch = text.charAt(i); |
| switch (ch) { |
| case '\r': |
| break; |
| case '\t': |
| result.append(' '); |
| break; |
| case '\n': |
| result.append(ENCODED_NEWLINE); |
| break; |
| case '\'': |
| result.append(ENCODED_SINGLE_QUOTE); |
| break; |
| case '\\': |
| result.append("\\\\"); //$NON-NLS-1$ |
| break; |
| default: |
| result.append(ch); |
| } |
| } |
| return result.toString(); |
| } |
| |
| /** |
| * Returns the child <code>OleControlSite</code> contained within the |
| * given <code>Composite</code>. |
| * |
| * @param composite |
| * a <code>Composite</code> object, presumably a |
| * <code>Browser</code> |
| * @return an <code>OleControlSite</code> object |
| */ |
| protected Control getControlSite(Composite composite) { |
| if (Platform.getOS().equals("win32")) { //$NON-NLS-1$ |
| Control[] controls = composite.getChildren(); |
| for (int i = 0; i < controls.length; i++) { |
| String controlClass = controls[i].getClass().getName(); |
| if (controlClass.equals("org.eclipse.swt.browser.WebSite")) { //$NON-NLS-1$ |
| return controls[i]; |
| } else if (controls[i] instanceof Composite) { |
| return getControlSite((Composite) controls[i]); |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Displays the given debug message to the console. |
| */ |
| protected void printDebugMessage(String method, String msg, String text) { |
| StringBuffer strBuf = new StringBuffer(); |
| strBuf.append("RichText[").append(editor.handle).append(']') //$NON-NLS-1$ |
| .append('.').append(method); |
| if (msg != null && msg.length() > 0) { |
| strBuf.append(": ").append(msg); //$NON-NLS-1$ |
| } |
| if (text != null && text.length() > 0) { |
| strBuf.append('\n').append(text); |
| } |
| System.out.println(strBuf); |
| } |
| |
| /** |
| * Displays the given debug message to the console. |
| */ |
| protected void printDebugMessage(String method, String msg) { |
| printDebugMessage(method, msg, null); |
| } |
| |
| /** |
| * Displays the given debug message to the console. |
| */ |
| protected void printDebugMessage(String method) { |
| printDebugMessage(method, null); |
| } |
| |
| public FindReplaceAction getFindReplaceAction() { |
| return findReplaceAction; |
| } |
| |
| public void setFindReplaceAction(FindReplaceAction findReplaceAction) { |
| if (findReplaceAction != null) { |
| if (this.findReplaceAction != null |
| && this.findReplaceAction != findReplaceAction) { |
| this.findReplaceAction.dispose(); |
| } |
| this.findReplaceAction = findReplaceAction; |
| this.findReplaceAction.setRichText(this); |
| } |
| } |
| |
| public void setInitialText(String text) { |
| setText(text); |
| initialText = text == null ? "" : text; //$NON-NLS-1$ |
| modified = false; |
| } |
| |
| } |