| //------------------------------------------------------------------------------ |
| // 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.net.URL; |
| import java.util.Iterator; |
| |
| import org.eclipse.core.commands.ParameterizedCommand; |
| import org.eclipse.epf.common.serviceability.Logger; |
| 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.jface.bindings.Binding; |
| import org.eclipse.jface.bindings.keys.KeySequence; |
| import org.eclipse.jface.bindings.keys.KeyStroke; |
| import org.eclipse.jface.bindings.keys.SWTKeySupport; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CTabFolder; |
| import org.eclipse.swt.custom.CTabItem; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.custom.ViewForm; |
| import org.eclipse.swt.dnd.DND; |
| import org.eclipse.swt.dnd.DropTarget; |
| import org.eclipse.swt.dnd.DropTargetEvent; |
| import org.eclipse.swt.dnd.DropTargetListener; |
| import org.eclipse.swt.dnd.HTMLTransfer; |
| import org.eclipse.swt.dnd.TextTransfer; |
| import org.eclipse.swt.dnd.Transfer; |
| 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.graphics.Point; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| 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; |
| import org.eclipse.ui.keys.IBindingService; |
| |
| /** |
| * The default rich text editor implementation. |
| * <p> |
| * The default rich text editor uses XHTML as the underlying markup language for |
| * the rich text content. It is implemented using a <code>ViewForm</code> |
| * control with a tool bar at the top, a tab folder that contains a |
| * <code>RichText</code> control for entering the rich text content, and a tab |
| * foler that contains a <code>StyleText</code> control for viewing and |
| * modifying the XHTML representation of the rich text content. |
| * |
| * @author Kelvin Low |
| * @author Jeff Hardy |
| * @since 1.0 |
| */ |
| public class RichTextEditor implements IRichTextEditor { |
| |
| // The HTML tab name. |
| protected static final String HTML_TAB_NAME = RichTextResources.htmlTab_text; |
| |
| // If true, log debugging info. |
| protected boolean debug; |
| |
| // The plug-in logger. |
| protected Logger logger; |
| |
| // The base path used for resolving links (<href>, <img>, etc.). |
| protected String basePath; |
| |
| // The editor form. |
| protected ViewForm form; |
| |
| // The editor tool bar. |
| protected IRichTextToolBar toolBar; |
| |
| // The editor content. |
| protected Composite content; |
| |
| // The editor tab folder. |
| protected CTabFolder tabFolder; |
| |
| // The rich text tab |
| protected CTabItem richTextTab; |
| |
| // The HTML source tab |
| protected CTabItem htmlTab; |
| |
| // The embedded rich text control. |
| protected IRichText richText; |
| |
| // The underlying HTML text editor. |
| protected StyledText sourceEdit; |
| |
| // Drop support |
| DropTarget sourceEditDropTarget; |
| |
| // HTML editor's context menu |
| protected Menu contextMenu; |
| |
| // Has the HTML source been modified? |
| protected boolean sourceModified = false; |
| |
| // The editor's editable flag. |
| protected boolean editable = true; |
| |
| // The modify listener for the sourceEdit control. |
| protected ModifyListener sourceEditModifyListener = new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| sourceModified = true; |
| if (richText != null && richText instanceof RichText) { |
| richText.notifyModifyListeners(); |
| } |
| } |
| }; |
| |
| // The deactivate listener for the sourceEdit control. |
| protected Listener sourceEditDeactivateListener = new Listener() { |
| public void handleEvent(Event event) { |
| if (sourceModified) { |
| updateRichText(sourceEdit.getText()); |
| setModified(true); |
| sourceModified = false; |
| } |
| } |
| }; |
| |
| // The key listener for the sourceEdit control. |
| protected KeyListener sourceEditKeyListener = new KeyListener() { |
| public void keyPressed(KeyEvent e) { |
| Object adapter = PlatformUI.getWorkbench().getAdapter( |
| IBindingService.class); |
| if (adapter != null && adapter instanceof IBindingService) { |
| int accel = SWTKeySupport |
| .convertEventToUnmodifiedAccelerator(e); |
| KeyStroke stroke = SWTKeySupport |
| .convertAcceleratorToKeyStroke(accel); |
| KeySequence seq = KeySequence.getInstance(stroke); |
| Binding bind = ((IBindingService) adapter).getPerfectMatch(seq); |
| if (bind != null) { |
| ParameterizedCommand command = bind |
| .getParameterizedCommand(); |
| if (command != null) { |
| String cmdId = command.getId(); |
| if (cmdId != null |
| && cmdId |
| .equals("org.eclipse.ui.edit.findReplace")) { //$NON-NLS-1$ |
| richText.getFindReplaceAction().execute(RichTextEditor.this); |
| } |
| } |
| } |
| } |
| } |
| |
| public void keyReleased(KeyEvent e) { |
| } |
| }; |
| |
| /** |
| * Creates a new instance. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * the editor style |
| */ |
| public RichTextEditor(Composite parent, int style) { |
| this(parent, style, null); |
| } |
| |
| /** |
| * Creates a new instance. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * the editor style |
| * @param basePath |
| * the base path used for resolving links |
| */ |
| public RichTextEditor(Composite parent, int style, String basePath) { |
| this.basePath = basePath; |
| debug = RichTextPlugin.getDefault().isDebugging(); |
| logger = RichTextPlugin.getDefault().getLogger(); |
| init(parent, style); |
| } |
| |
| /** |
| * Initializes this editor. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * the editor style |
| */ |
| protected void init(Composite parent, int style) { |
| try { |
| form = new ViewForm(parent, style); |
| form.marginHeight = 0; |
| form.marginWidth = 0; |
| |
| toolBar = new RichTextToolBar(form, SWT.FLAT, this); |
| |
| content = new Composite(form, SWT.FLAT); |
| GridLayout layout = new GridLayout(); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| content.setLayout(layout); |
| |
| tabFolder = createEditorTabFolder(content, style); |
| |
| form.setTopLeft((Control) toolBar); |
| form.setContent(content); |
| } catch (Exception e) { |
| logger.logError(e); |
| } |
| } |
| |
| /** |
| * Returns the form control. |
| * |
| * @return the form control |
| */ |
| public Control getControl() { |
| return form; |
| } |
| |
| /** |
| * Returns the rich text control embedded within this editor. |
| */ |
| public IRichText getRichTextControl() { |
| return richText; |
| } |
| |
| /** |
| * Sets the layout data. |
| * |
| * @param layoutData |
| * the layout data to set |
| */ |
| public void setLayoutData(Object layoutData) { |
| if (form != null) { |
| form.setLayoutData(layoutData); |
| } |
| } |
| |
| /** |
| * Returns the layout data. |
| * |
| * @return the editor's layout data |
| */ |
| public Object getLayoutData() { |
| if (form != null) { |
| return form.getLayoutData(); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets focus to this editor. |
| */ |
| public void setFocus() { |
| if (richText != null) { |
| richText.setFocus(); |
| } |
| setSelection(0); |
| } |
| |
| /** |
| * Tells the control it does not have focus. |
| */ |
| public void setBlur() { |
| if (richText != null) { |
| richText.setBlur(); |
| } |
| } |
| |
| /** |
| * Checks whether this editor has focus. |
| * |
| * @return <code>true</code> if this editor has the user-interface focus |
| */ |
| public boolean hasFocus() { |
| if (richText != null) { |
| return richText.hasFocus(); |
| } |
| return false; |
| } |
| |
| /** |
| * Selects the Rich Text or HTML tab. |
| * |
| * @param index |
| * <code>0</code> for the Rich Text tab, <code>1</code> for |
| * the HTML tab. |
| */ |
| public void setSelection(int index) { |
| if (tabFolder != null) { |
| tabFolder.setSelection(index); |
| } |
| } |
| |
| /** |
| * Returns the base path used for resolving text and image links. |
| * |
| * @return the base path used for resolving links specified with <href>, |
| * <img>, etc. |
| */ |
| 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() { |
| if (richText != null) { |
| return richText.getCopyURL(); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the base URL of the rich text control whose content was last copied |
| * to the clipboard. |
| */ |
| public void setCopyURL() { |
| if (richText != null) { |
| richText.setCopyURL(); |
| } |
| } |
| |
| /** |
| * Returns the editable state. |
| * |
| * @return <code>true</code> if the content can be edited |
| */ |
| public boolean getEditable() { |
| return editable; |
| } |
| |
| /** |
| * Sets the editable state. |
| * |
| * @param editable |
| * the editable state |
| */ |
| public void setEditable(boolean editable) { |
| this.editable = editable; |
| if (toolBar != null && tabFolder != null) { |
| if (tabFolder.getSelection() == richTextTab) { |
| toolBar.updateToolBar(editable); |
| } |
| } |
| if (richText != null) { |
| richText.setEditable(editable); |
| } |
| if (sourceEdit != null) { |
| sourceEdit.setEditable(editable); |
| sourceEdit.getEditable(); |
| } |
| } |
| |
| /** |
| * Checks whether the content has been modified. |
| * |
| * @return <code>true</code> if the content has been modified |
| */ |
| public boolean getModified() { |
| if (richText != null) { |
| return richText.getModified(); |
| } |
| return false; |
| } |
| |
| /** |
| * Sets the modified state. |
| * |
| * @param modified |
| * the modified state |
| */ |
| public void setModified(boolean modified) { |
| if (richText != null) { |
| richText.setModified(modified); |
| } |
| } |
| |
| /** |
| * Returns the rich text content. |
| * |
| * @return the rich text content formatted in XHTML |
| */ |
| public String getText() { |
| if (sourceModified) { |
| setText(sourceEdit.getText()); |
| setModified(true); |
| sourceModified = false; |
| } |
| if (richText != null) { |
| return richText.getText(); |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Sets the rich text content. |
| * |
| * @param text |
| * the rich text content in XHTML format |
| */ |
| public void setText(String text) { |
| if (richText != null) { |
| richText.setText(text); |
| } |
| sourceModified = false; |
| if (tabFolder != null) { |
| if (toolBar != null) { |
| toolBar.updateToolBar(editable); |
| } |
| if (sourceEdit != null) { |
| sourceEdit.removeModifyListener(sourceEditModifyListener); |
| sourceEdit.setText(getText()); |
| sourceEdit.addModifyListener(sourceEditModifyListener); |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.epf.richtext.IRichText#checkModify() |
| */ |
| public void checkModify() { |
| richText.checkModify(); |
| if (sourceModified) { |
| notifyModifyListeners(); |
| } |
| if (debug) { |
| printDebugMessage("checkModify", "modified=" + sourceModified); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| |
| /** |
| * Restores the rich text content back to the initial value. |
| */ |
| public void restoreText() { |
| if (richText != null) { |
| richText.restoreText(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.epf.richtext.IRichText#getSelected() |
| */ |
| public RichTextSelection getSelected() { |
| if (tabFolder.getSelection() == htmlTab) { |
| String HTMLsource = sourceEdit.getText(); |
| Point sel = sourceEdit.getSelectionRange(); |
| int selStartIndex = sel.x; |
| int selEndIndex = sel.x + sel.y - 1; |
| richText.getSelected().clear(); |
| richText.getSelected().setText(HTMLsource.substring(selStartIndex, selEndIndex + 1)); |
| } |
| return richText.getSelected(); |
| } |
| |
| /** |
| * 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 (richText != null) { |
| richText.getData(key); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets an application specific property name and value. |
| * |
| * @param key |
| * the name of the property |
| * @param value |
| * the new value for the property |
| */ |
| public void setData(String key, Object value) { |
| if (richText != null) { |
| richText.setData(key, value); |
| } |
| } |
| |
| /** |
| * 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) { |
| if (richText != null) { |
| return richText.executeCommand(command); |
| } |
| return 0; |
| } |
| |
| /** |
| * 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 (richText != null) { |
| return richText.executeCommand(command, param); |
| } |
| return 0; |
| } |
| |
| /** |
| * 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 (richText != null) { |
| return richText.executeCommand(command, params); |
| } |
| return 0; |
| } |
| |
| /** |
| * Disposes the operating system resources allocated by this editor. |
| */ |
| public void dispose() { |
| if (contextMenu != null && !contextMenu.isDisposed()) { |
| contextMenu.dispose(); |
| contextMenu = null; |
| } |
| if (sourceEditDropTarget != null) { |
| sourceEditDropTarget.dispose(); |
| sourceEditDropTarget = null; |
| } |
| if (sourceEdit != null) { |
| sourceEdit.removeModifyListener(sourceEditModifyListener); |
| sourceEdit.removeListener(SWT.Deactivate, |
| sourceEditDeactivateListener); |
| sourceEdit.removeKeyListener(sourceEditKeyListener); |
| sourceEditModifyListener = null; |
| sourceEditDeactivateListener = null; |
| sourceEditKeyListener = null; |
| } |
| if (richText != null) { |
| richText.dispose(); |
| richText = null; |
| } |
| } |
| |
| /** |
| * Checks whether this control has been disposed. |
| * |
| * @return <code>true</code> if this control is disposed successfully |
| */ |
| public boolean isDisposed() { |
| if (richText != null) { |
| return richText.isDisposed(); |
| } |
| return true; |
| } |
| |
| /** |
| * Returns the modify listeners attached to this editor. |
| * |
| * @return an iterator for retrieving the modify listeners |
| */ |
| public Iterator getModifyListeners() { |
| if (richText != null) { |
| richText.getModifyListeners(); |
| } |
| return null; |
| } |
| |
| /** |
| * Adds a listener to the collection of listeners who will be notified when |
| * keys are pressed and released within this editor. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addKeyListener(KeyListener listener) { |
| if (richText != null) { |
| richText.addKeyListener(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when keys are pressed and released within this editor. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeKeyListener(KeyListener listener) { |
| if (richText != null) { |
| richText.removeKeyListener(listener); |
| } |
| } |
| |
| /** |
| * Adds a listener to the collection of listeners who will be notified when |
| * the content of this editor is modified. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addModifyListener(ModifyListener listener) { |
| if (richText != null) { |
| richText.addModifyListener(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when the content of this editor is modified. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeModifyListener(ModifyListener listener) { |
| if (richText != null) { |
| richText.removeModifyListener(listener); |
| } |
| } |
| |
| /** |
| * Adds the listener to the collection of listeners who will be notifed when |
| * this editor is disposed. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addDisposeListener(DisposeListener listener) { |
| if (richText != null) { |
| richText.addDisposeListener(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when this editor is disposed. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeDisposeListener(DisposeListener listener) { |
| if (richText != null) { |
| richText.removeDisposeListener(listener); |
| } |
| } |
| |
| /** |
| * Adds a listener to the collection of listeners who will be notified when |
| * help events are generated for this editor. |
| * |
| * @param listener |
| * the listener which should be notified |
| */ |
| public void addHelpListener(HelpListener listener) { |
| if (richText != null) { |
| richText.addHelpListener(listener); |
| } |
| } |
| |
| /** |
| * Removes a listener from the collection of listeners who will be notified |
| * when help events are generated for this editor. |
| * |
| * @param listener |
| * the listener which should no longer be notified |
| */ |
| public void removeHelpListener(HelpListener listener) { |
| if (richText != null) { |
| richText.removeHelpListener(listener); |
| } |
| } |
| |
| /** |
| * Adds the listener to the collection of listeners who will be notifed when |
| * an event of the given type occurs within this editor. |
| * |
| * @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 (richText != null) { |
| richText.addListener(eventType, listener); |
| } |
| } |
| |
| /** |
| * Removes the listener from the collection of listeners who will be notifed |
| * when an event of the given type occurs within this editor. |
| * |
| * @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 (richText != null) { |
| richText.removeListener(eventType, listener); |
| } |
| } |
| |
| /** |
| * Returns the event listeners attached to this editor. |
| * |
| * @return an iterator for retrieving the event listeners attached to this |
| * editor |
| */ |
| public Iterator getListeners() { |
| if (richText != null) { |
| return richText.getListeners(); |
| } |
| return null; |
| } |
| |
| /** |
| * Notifies the modify listeners that the rich text editor content has |
| * changed. |
| */ |
| public void notifyModifyListeners() { |
| if (richText != null) { |
| Event event = new Event(); |
| event.display = Display.getCurrent(); |
| event.widget = richText.getControl(); |
| |
| for (Iterator i = getModifyListeners(); i != null && i.hasNext();) { |
| ModifyListener listener = (ModifyListener) i.next(); |
| listener.modifyText(new ModifyEvent(event)); |
| } |
| } |
| } |
| |
| /** |
| * Fills the tool bar with action items. |
| * |
| * @param toolBar |
| * a tool bar contain rich text actions |
| */ |
| public void fillToolBar(IRichTextToolBar toolBar) { |
| } |
| |
| /** |
| * Creates the underlying rich text control. |
| * |
| * @param parent |
| * the parent composite |
| * @param style |
| * the style for the control |
| * @param basePath |
| * the path used for resolving links |
| */ |
| protected IRichText createRichTextControl(Composite parent, int style, |
| String basePath) { |
| return new RichText(parent, style, basePath); |
| } |
| |
| /** |
| * Creates the editor tab folder. |
| * |
| * @param parent |
| * the parent control |
| * @param style |
| * the style for the control |
| * @return a new editor toolbar |
| */ |
| protected CTabFolder createEditorTabFolder(Composite parent, int style) { |
| CTabFolder folder = new CTabFolder(parent, SWT.FLAT | SWT.BOTTOM); |
| folder.setLayout(new GridLayout(1, true)); |
| folder.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| |
| Composite richTextComposite = new Composite(folder, SWT.FLAT); |
| GridLayout richTextCompositeLayout = new GridLayout(1, false); |
| richTextCompositeLayout.marginHeight = 0; |
| richTextCompositeLayout.marginWidth = 0; |
| richTextComposite.setLayout(richTextCompositeLayout); |
| richTextComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| |
| richText = createRichTextControl(richTextComposite, style, basePath); |
| richText.setData(PROPERTY_NAME, this); |
| richText.getFindReplaceAction().setRichText(this); |
| |
| richTextTab = new CTabItem(folder, SWT.FLAT); |
| richTextTab.setText(RichTextResources.richTextTab_text); |
| richTextTab.setToolTipText(RichTextResources.richTextTab_toolTipText); |
| richTextTab.setControl(richTextComposite); |
| |
| Composite htmlComposite = new Composite(folder, SWT.FLAT); |
| htmlComposite.setLayout(new FillLayout()); |
| |
| sourceEdit = new StyledText(htmlComposite, SWT.FLAT | SWT.MULTI |
| | SWT.WRAP | SWT.V_SCROLL); |
| sourceEdit.addModifyListener(sourceEditModifyListener); |
| sourceEdit.addListener(SWT.Deactivate, sourceEditDeactivateListener); |
| sourceEdit.addKeyListener(sourceEditKeyListener); |
| contextMenu = new Menu(parent.getShell(), SWT.POP_UP); |
| sourceEdit.setMenu(contextMenu); |
| addDropSupportToStyledText(); |
| fillContextMenu(contextMenu); |
| |
| htmlTab = new CTabItem(folder, SWT.NONE); |
| htmlTab.setText(HTML_TAB_NAME); |
| htmlTab.setToolTipText(RichTextResources.htmlTab_toolTipText); |
| htmlTab.setControl(htmlComposite); |
| |
| folder.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| CTabItem item = (CTabItem) event.item; |
| if (item.getText().equals(HTML_TAB_NAME)) { |
| sourceEdit.removeModifyListener(sourceEditModifyListener); |
| sourceEdit.setText(getText()); |
| sourceModified = false; |
| sourceEdit.addModifyListener(sourceEditModifyListener); |
| if (toolBar != null) { |
| toolBar.updateToolBar(editable); |
| } |
| sourceEdit.setCaretOffset(richText.getSelected().getOffsetStart()); |
| } else { |
| updateRichText(sourceEdit.getText()); |
| setModified(true); |
| if (toolBar != null) { |
| toolBar.updateToolBar(editable); |
| } |
| } |
| } |
| }); |
| fillToolBar(toolBar); |
| |
| folder.setSelection(0); |
| |
| return folder; |
| } |
| |
| /** |
| * Returns the HTML source edit control. |
| * |
| * @return a <code>StyleText</code> object. |
| */ |
| public StyledText getSourceEdit() { |
| return sourceEdit; |
| } |
| |
| /** |
| * Inserts text at the selection (overwriting the selection). |
| */ |
| public void addHTML(String text) { |
| if (text == null || text.length() == 0) |
| return; |
| if (tabFolder.getSelection() == richTextTab) { |
| executeCommand(RichTextCommand.ADD_HTML, text); |
| } else if (tabFolder.getSelection() == htmlTab) { |
| String oldHTML = sourceEdit.getText(); |
| Point sel = sourceEdit.getSelectionRange(); |
| int selStartIndex = sel.x; |
| int selEndIndex = sel.x + sel.y - 1; |
| String newHTML = oldHTML.substring(0, selStartIndex) + text |
| + oldHTML.substring(selEndIndex + 1); |
| sourceEdit.removeModifyListener(sourceEditModifyListener); |
| sourceEdit.setText(newHTML); |
| sourceEdit.addModifyListener(sourceEditModifyListener); |
| updateRichText(newHTML); |
| } |
| } |
| |
| |
| /** |
| * Inserts an image at the selection (overwriting the selection). |
| */ |
| public void addImage(String imageURL, String height, String width, String altTag) { |
| if (tabFolder.getSelection() == richTextTab) { |
| executeCommand( |
| RichTextCommand.ADD_IMAGE, |
| new String[] { |
| imageURL, |
| height, width, altTag }); |
| } else if (tabFolder.getSelection() == htmlTab) { |
| StringBuffer imageLink = new StringBuffer(); |
| // order of these attributes is the same as JTidy'ed HTML |
| imageLink.append("<img"); //$NON-NLS-1$ |
| if (height.length() > 0) { |
| imageLink.append(" height=\"" + height + "\""); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| if (altTag.length() > 0) { |
| imageLink.append(" alt=\"" + altTag + "\""); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| imageLink.append(" src=\"" + imageURL + "\""); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (width.length() > 0) { |
| imageLink.append(" width=\"" + width + "\""); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| imageLink.append(" />"); //$NON-NLS-1$ |
| String oldHTML = sourceEdit.getText(); |
| Point sel = sourceEdit.getSelectionRange(); |
| int selStartIndex = sel.x; |
| int selEndIndex = sel.x + sel.y - 1; |
| String newHTML = oldHTML.substring(0, selStartIndex) + imageLink.toString() |
| + oldHTML.substring(selEndIndex + 1); |
| sourceEdit.removeModifyListener(sourceEditModifyListener); |
| sourceEdit.setText(newHTML); |
| sourceEdit.addModifyListener(sourceEditModifyListener); |
| updateRichText(newHTML); |
| } |
| } |
| |
| /** |
| * Checks whether the HTML tab is selected. |
| * |
| * @return <code>true</code> if the HTML tab is selected. |
| */ |
| public boolean isHTMLTabSelected() { |
| return (tabFolder.getSelection() == htmlTab); |
| } |
| |
| /** |
| * 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(); |
| action.execute(RichTextEditor.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(); |
| action.execute(RichTextEditor.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(); |
| action.execute(RichTextEditor.this); |
| } |
| }); |
| |
| final MenuItem pastePlainTextItem = new MenuItem(contextMenu, SWT.PUSH); |
| pastePlainTextItem.setText(RichTextResources.pastePlainTextAction_text); |
| pastePlainTextItem.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| PastePlainTextAction action = new PastePlainTextAction(); |
| action.execute(RichTextEditor.this); |
| } |
| }); |
| |
| contextMenu.addMenuListener(new MenuListener() { |
| public void menuHidden(MenuEvent e) { |
| } |
| |
| public void menuShown(MenuEvent e) { |
| String selectedText = getSelected().getText(); |
| boolean selection = selectedText.length() > 0; |
| cutItem.setEnabled(editable && selection); |
| copyItem.setEnabled(selection); |
| pasteItem.setEnabled(editable); |
| pastePlainTextItem.setEnabled(editable); |
| } |
| }); |
| } |
| |
| /** |
| * Updates the content of the rich text control without updating the HTML |
| * source editor. |
| * <p> |
| * This method should be called by the HTML source editor to sync up its |
| * content with the rich text control. |
| * |
| * @param text |
| * the rich text content in XHTML format |
| */ |
| private void updateRichText(String text) { |
| if (richText != null) { |
| richText.setText(text); |
| richText.checkModify(); |
| } |
| sourceModified = false; |
| if (tabFolder != null) { |
| if (toolBar != null) { |
| toolBar.updateToolBar(editable); |
| } |
| } |
| } |
| |
| private void addDropSupportToStyledText() { |
| // this function based heavily on the example at: |
| // http://www.eclipse.org/articles/Article-SWT-DND/DND-in-SWT.html |
| |
| // Allow data to be copied to the drop target |
| int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT; |
| sourceEditDropTarget = new DropTarget(sourceEdit, operations); |
| |
| // Receive data in Text or HTML format |
| final TextTransfer textTransfer = TextTransfer.getInstance(); |
| final HTMLTransfer htmlTransfer = HTMLTransfer.getInstance(); |
| Transfer[] types = new Transfer[] {htmlTransfer, textTransfer}; |
| sourceEditDropTarget.setTransfer(types); |
| |
| sourceEditDropTarget.addDropListener(new DropTargetListener() { |
| public void dragEnter(DropTargetEvent event) { |
| if (event.detail == DND.DROP_DEFAULT) { |
| if ((event.operations & DND.DROP_COPY) != 0) { |
| event.detail = DND.DROP_COPY; |
| } else { |
| event.detail = DND.DROP_NONE; |
| } |
| } |
| // will accept text but prefer to have HTML dropped |
| for (int i = 0; i < event.dataTypes.length; i++) { |
| if (htmlTransfer.isSupportedType(event.dataTypes[i])){ |
| event.currentDataType = event.dataTypes[i]; |
| break; |
| } |
| } |
| } |
| public void dragOver(DropTargetEvent event) { |
| event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_INSERT_AFTER | DND.FEEDBACK_SCROLL; |
| } |
| public void dragOperationChanged(DropTargetEvent event) { |
| if (event.detail == DND.DROP_DEFAULT) { |
| if ((event.operations & DND.DROP_COPY) != 0) { |
| event.detail = DND.DROP_COPY; |
| } else { |
| event.detail = DND.DROP_NONE; |
| } |
| } |
| } |
| public void dragLeave(DropTargetEvent event) { |
| } |
| public void dropAccept(DropTargetEvent event) { |
| } |
| public void drop(DropTargetEvent event) { |
| if (textTransfer.isSupportedType(event.currentDataType) || |
| htmlTransfer.isSupportedType(event.currentDataType)) { |
| String text = (String)event.data; |
| addHTML(text); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Displays the given debug message to the console. |
| */ |
| private void printDebugMessage(String method, String msg, String text) { |
| StringBuffer strBuf = new StringBuffer(); |
| strBuf.append("RichTextEditor[").append(richText.getControl().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. |
| */ |
| private void printDebugMessage(String method, String msg) { |
| printDebugMessage(method, msg, null); |
| } |
| |
| public FindReplaceAction getFindReplaceAction() { |
| return richText.getFindReplaceAction(); |
| } |
| |
| public void setFindReplaceAction(FindReplaceAction findReplaceAction) { |
| richText.setFindReplaceAction(findReplaceAction); |
| richText.getFindReplaceAction().setRichText(this); |
| } |
| } |