/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.internal.notes; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.ITextInputListener; import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.jface.viewers.IInputSelectionProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.graphics.RGB; 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.xmind.ui.richtext.Hyperlink; import org.xmind.ui.richtext.IRichDocument; import org.xmind.ui.richtext.IRichDocumentListener; import org.xmind.ui.richtext.IRichTextActionBarContributor; import org.xmind.ui.richtext.IRichTextEditViewer; import org.xmind.ui.richtext.ImagePlaceHolder; import org.xmind.ui.richtext.LineStyle; import org.xmind.ui.richtext.RichTextEditViewer; public class TopicNotesViewer implements INotesContentViewer, IInputSelectionProvider { private class SelectionSynchronizer implements ISelectionProvider, ISelectionChangedListener { private List<ISelectionChangedListener> selectionChangedListeners = null; private ISelection selection; private boolean synchronizingSelection = false; public void addSelectionChangedListener( ISelectionChangedListener listener) { if (selectionChangedListeners == null) selectionChangedListeners = new ArrayList<ISelectionChangedListener>(); selectionChangedListeners.add(listener); } public ISelection getSelection() { return selection == null ? StructuredSelection.EMPTY : selection; } public void removeSelectionChangedListener( ISelectionChangedListener listener) { if (selectionChangedListeners == null) return; selectionChangedListeners.remove(listener); } public void setSelection(ISelection selection) { this.selection = selection; if (implementation != null) { synchronizingSelection = true; implementation.setSelection(selection); synchronizingSelection = false; } } public void selectionChanged(SelectionChangedEvent event) { if (synchronizingSelection) return; fireSelectionChanged(event); } private void fireSelectionChanged(SelectionChangedEvent event) { if (selectionChangedListeners == null) return; for (Object o : selectionChangedListeners.toArray()) { ((ISelectionChangedListener) o).selectionChanged(event); } } } private class ModificationListener implements IDocumentListener, IRichDocumentListener, ITextInputListener { private boolean modified = false; public void textStyleChanged(IRichDocument document, StyleRange[] oldTextStyles, StyleRange[] newTextStyles) { modified = true; } public void lineStyleChanged(IRichDocument document, LineStyle[] oldLineStyles, LineStyle[] newLineStyles) { modified = true; } public void imageChanged(IRichDocument document, ImagePlaceHolder[] oldImages, ImagePlaceHolder[] newImages) { modified = true; } public void hyperlinkChanged(IRichDocument document, Hyperlink[] oldHyperlinks, Hyperlink[] newHyperlinks) { modified = true; } public void documentAboutToBeChanged(DocumentEvent event) { } public void documentChanged(DocumentEvent event) { modified = true; } /* * (non-Javadoc) * * @see * org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged * (org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) */ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { } /* * (non-Javadoc) * * @see * org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org * .eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) */ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { if (oldInput != null) { oldInput.removeDocumentListener(this); if (oldInput instanceof IRichDocument) { ((IRichDocument) oldInput).removeRichDocumentListener(this); } } if (newInput != null) { newInput.addDocumentListener(this); if (newInput instanceof IRichDocument) { ((IRichDocument) newInput).addRichDocumentListener(this); } } } /** * @return the modified */ public boolean isModified() { return modified; } public void reset() { modified = false; } } private IRichTextEditViewer implementation; private Object input; private SelectionSynchronizer selectionProvider; private IRichTextActionBarContributor contributor; private ModificationListener modificationListener; private Composite composite; public TopicNotesViewer() { } public TopicNotesViewer(IRichTextActionBarContributor contributor) { this.contributor = contributor; } public void setContributor(IRichTextActionBarContributor contributor) { this.contributor = contributor; } public Control createControl(Composite parent) { composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_WHITE)); GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; layout.horizontalSpacing = 0; layout.verticalSpacing = 0; composite.setLayout(layout); composite.setLayoutData(new GridData(GridData.FILL_BOTH)); createControl(composite, IRichTextEditViewer.DEFAULT_CONTROL_STYLE); return composite; } public void createControl(Composite parent, int textControlStyle) { implementation = new RichTextEditViewer(parent, textControlStyle, contributor); TextViewer viewer = implementation.getTextViewer(); RGB red = new RGB(183, 0, 91); viewer.setHyperlinkPresenter(new DefaultHyperlinkPresenter(red)); viewer.setHyperlinkDetectors( new IHyperlinkDetector[] { new NotesHyperlinkDetector() }, SWT.MOD1); modificationListener = new ModificationListener(); viewer.addTextInputListener(modificationListener); IRichDocument document = getDocument(); implementation.setInput(document); Control control = implementation.getControl(); control.setLayoutData(new GridData(GridData.FILL_BOTH)); } private IRichDocument getDocument() { if (input instanceof IRichDocument) return (IRichDocument) input; if (input instanceof IAdaptable) { return (IRichDocument) ((IAdaptable) input) .getAdapter(IRichDocument.class); } return null; } public Control getControl() { return implementation == null ? null : implementation.getControl(); } public IRichTextEditViewer getImplementation() { return implementation; } public void setInput(Object input) { this.input = input; if (implementation != null) { implementation.setInput(getDocument()); } } public Object getInput() { return input; } public void addSelectionChangedListener(ISelectionChangedListener listener) { getSelectionProvider().addSelectionChangedListener(listener); } private SelectionSynchronizer getSelectionProvider() { if (selectionProvider == null) { selectionProvider = new SelectionSynchronizer(); } return selectionProvider; } public ISelection getSelection() { return getSelectionProvider().getSelection(); } public void removeSelectionChangedListener( ISelectionChangedListener listener) { if (selectionProvider != null) { selectionProvider.removeSelectionChangedListener(listener); } } public void setSelection(ISelection selection) { getSelectionProvider().setSelection(selection); } public boolean hasModified() { return modificationListener == null || modificationListener.isModified(); } public void resetModified() { if (modificationListener != null) { modificationListener.reset(); } } public void dispose() { composite.dispose(); } }