package org.xmind.ui.internal.comments;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.text.DefaultTextDoubleClickStrategy;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.ITextListener;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.TextViewerUndoManager;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CaretEvent;
import org.eclipse.swt.custom.CaretListener;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Caret;
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.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.xmind.core.Core;
import org.xmind.core.IComment;
import org.xmind.core.IWorkbook;
import org.xmind.core.event.ICoreEventListener;
import org.xmind.core.event.ICoreEventRegistration;
import org.xmind.core.event.ICoreEventSource2;
import org.xmind.core.internal.dom.DOMConstants;
import org.xmind.gef.command.Command;
import org.xmind.gef.command.ICommandStack;
import org.xmind.gef.ui.editor.IGraphicalEditor;
import org.xmind.ui.commands.AddCommentCommand;
import org.xmind.ui.commands.DeleteCommentCommand;
import org.xmind.ui.commands.ModifyCommentCommand;
import org.xmind.ui.internal.MindMapMessages;
import org.xmind.ui.internal.e4models.CommentsPart;
import org.xmind.ui.internal.spelling.SpellingPlugin;
import org.xmind.ui.internal.spellsupport.SpellingSupport;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.richtext.RichTextDamagerRepairer;
import org.xmind.ui.richtext.RichTextScanner;
import org.xmind.ui.texteditor.ISpellingActivation;
import org.xmind.ui.util.TextFormatter;
public class CommentTextViewer {
private static class LessLatencyTextViewer extends TextViewer {
private LessLatencyTextViewer(Composite parent, int styles) {
super(parent, styles);
}
@Override
protected int getEmptySelectionChangedEventDelay() {
return 100;
}
}
private static final int EXTRA_WIDTH = 22;
private static int DEFAULT_STYLE = SWT.MULTI | SWT.WRAP | SWT.NO_SCROLL;
private Color originalColor;
private Color hoverColor;
private Color selectColor;
private IComment comment;
private String objectId;
private IWorkbook workbook;
private ICommentsActionBarContributor contributor;
private ISelectionProvider selectionProvider;
private ICommentTextViewerContainer container;
private ISpellingActivation spellingActivation;
private IPreferenceStore spellingPreferences;
private boolean editable = (DEFAULT_STYLE & SWT.READ_ONLY) == 0;
private Composite control;
private TextViewer textViewer;
private MenuManager textContextMenuManager;
private Menu textContextMenu;
private IDocument document;
private int textHeight = 17;
private ICoreEventRegistration saveCommentReg;
private MouseListener mouseListener;
private ISelectionChangedListener selectionChangedListener;
private FocusListener textFocusListener;
private CaretListener caretListener;
private ISelectionChangedListener postSelectionChangedListener;
private IPropertyChangeListener propertyChangeListener;
private ControlListener controlListener;
private ITextListener textListener;
private ModifyListener modifyListener;
private IGraphicalEditor targetEditor;
private StyleRange styleRange;
private Label timeLabel;
private Control modifyCommentActionBar;
private boolean isLinkHovering;
private Listener listener;
private Menu contextMenu;
private ResourceManager resources;
public CommentTextViewer(IComment comment, String objectId,
IWorkbook workbook, ICommentsActionBarContributor contributor,
ISelectionProvider selectionProvider,
ICommentTextViewerContainer container,
IGraphicalEditor targetEditor) {
this.comment = comment;
this.objectId = objectId;
this.workbook = workbook;
this.contributor = contributor;
this.selectionProvider = selectionProvider;
this.container = container;
this.targetEditor = targetEditor;
resources = new LocalResourceManager(JFaceResources.getResources(),
container.getContentComposite());
initColors();
}
private void initColors() {
if (container instanceof CommentsPopup) {
originalColor = CommentsPopup.BG_COLOR;
hoverColor = (Color) resources
.get(ColorUtils.toDescriptor("#f0f0f0")); //$NON-NLS-1$
selectColor = (Color) resources
.get(ColorUtils.toDescriptor("#eaeaea")); //$NON-NLS-1$
} else if (container instanceof CommentsPart) {
originalColor = (Color) resources
.get(ColorUtils.toDescriptor(CommentsPart.BG_COLOR));
hoverColor = (Color) resources
.get(ColorUtils.toDescriptor("#f9f9f9")); //$NON-NLS-1$
selectColor = (Color) resources
.get(ColorUtils.toDescriptor("#f5f5f5")); //$NON-NLS-1$
}
}
public Control createControl(Composite parent) {
control = new Composite(parent, SWT.NONE);
control.setBackground(parent.getBackground());
control.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 7;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
control.setLayout(layout);
createContentArea(control);
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
handleControlDispose(e);
}
});
//restore last editing.
if (comment != null && comment == container.getEditingComment()) {
startEditing();
container.setModified(false);
container.setEditingComment(null);
}
return control;
}
private void createContentArea(Composite parent) {
if (comment == null) {
createNullContentArea(parent);
} else {
createNotNullContentArea(parent);
}
}
private void createNullContentArea(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setBackground(parent.getBackground());
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout layout = new GridLayout(1, false);
layout.marginWidth = 10;
layout.marginHeight = 0;
layout.verticalSpacing = 5;
composite.setLayout(layout);
Composite marginComposite = new Composite(composite, SWT.NONE);
marginComposite.setBackground(parent.getBackground());
marginComposite.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#ffffff"))); //$NON-NLS-1$
marginComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout layout2 = new GridLayout(1, false);
layout2.marginWidth = 1;
layout2.marginHeight = 1;
marginComposite.setLayout(layout2);
createNullTextControl(marginComposite);
createAddCommentActionBar(composite);
marginComposite.setBackground(
(Color) resources.get(ColorUtils.toDescriptor("#298fca"))); //$NON-NLS-1$
}
private void createNullTextControl(Composite parent) {
textViewer = createTextViewer(parent, DEFAULT_STYLE);
initTextViewer(textViewer);
setEditable(true);
StyledText text = textViewer.getTextWidget();
text.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
text.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#000000"))); //$NON-NLS-1$
text.setFont(JFaceResources.getDefaultFont());
GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
gridData.horizontalIndent = 0;
gridData.verticalIndent = 0;
gridData.minimumHeight = 110;
IDocument contentDocument = new Document(null);
setDocument(contentDocument);
ScrolledComposite sc = container.getScrolledComposite();
if (sc.getClientArea().width != 0) {
gridData.widthHint = sc.getClientArea().width - EXTRA_WIDTH;
}
text.setLayoutData(gridData);
sc.addControlListener(getControlListener());
text.addModifyListener(getModifyListener());
text.addFocusListener(getFocusListener());
text.setFocus();
}
private void createAddCommentActionBar(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
composite.setBackground(parent.getBackground());
GridLayout layout = new GridLayout(2, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
composite.setLayout(layout);
IAction cancelAddCommentAction = new Action() {
@Override
public void run() {
resetModified();
isLinkHovering = false;
container.cancelCreateComment();
}
};
Hyperlink cancelLink = createLink(composite,
MindMapMessages.Comment_Cancel_text,
MindMapMessages.Comment_Cancel_tooltip, cancelAddCommentAction);
cancelLink.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false));
IAction addCommentAction = new Action() {
@Override
public void run() {
addComment();
}
};
Hyperlink addLink = createLink(composite,
MindMapMessages.AddCommentLink_text,
MindMapMessages.AddCommentLink_tooltip, addCommentAction);
addLink.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, true, false));
}
private Hyperlink createLink(Composite parent, String text, String toolTip,
final IAction action) {
final Hyperlink link = new Hyperlink(parent, SWT.NONE);
link.setBackground(link.getParent().getBackground());
link.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#0082F9"))); //$NON-NLS-1$
link.setFont((Font) resources.get(
JFaceResources.getDefaultFontDescriptor().increaseHeight(1)));
link.setText(text);
link.setToolTipText(toolTip);
link.setUnderlined(false);
link.addHyperlinkListener(new IHyperlinkListener() {
public void linkEntered(HyperlinkEvent e) {
link.setUnderlined(true);
isLinkHovering = true;
}
public void linkExited(HyperlinkEvent e) {
link.setUnderlined(false);
isLinkHovering = false;
}
public void linkActivated(HyperlinkEvent e) {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
try {
action.run();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
return link;
}
private void createNotNullContentArea(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
composite.setBackground(parent.getBackground());
GridLayout layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 7;
layout.horizontalSpacing = 0;
composite.setLayout(layout);
Composite composite2 = new Composite(composite, SWT.NONE);
composite2.setBackground(parent.getBackground());
composite2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout layout4 = new GridLayout(1, false);
layout4.marginWidth = 10 - layout.marginWidth;
layout4.marginHeight = 0;
composite2.setLayout(layout4);
Composite marginComposite = new Composite(composite2, SWT.NONE);
marginComposite.setBackground(parent.getBackground());
marginComposite.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#ffffff"))); //$NON-NLS-1$
marginComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout layout2 = new GridLayout(1, false);
layout2.marginWidth = 1;
layout2.marginHeight = 1;
marginComposite.setLayout(layout2);
createNotNullTextControl(marginComposite);
Composite composite3 = new Composite(parent, SWT.NONE);
composite3.setBackground(parent.getBackground());
composite3.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout layout3 = new GridLayout(1, false);
layout3.marginWidth = 10;
layout3.marginHeight = 0;
composite3.setLayout(layout3);
createTimeLabel(composite3);
createModifyCommentActionBar(composite3);
modifyCommentActionBar.setVisible(false);
((GridData) modifyCommentActionBar.getLayoutData()).exclude = true;
addMouseFilter();
CommentsUtils.addRecursiveMouseListener(control, getMouseListener(),
null);
addContextMenu();
selectionProvider
.addSelectionChangedListener(getSelectionChangedListener());
}
private void createNotNullTextControl(Composite parent) {
textViewer = createTextViewer(parent, DEFAULT_STYLE);
initTextViewer(textViewer);
setEditable(false);
StyledText text = textViewer.getTextWidget();
text.setBackground(parent.getBackground());
text.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#45464a"))); //$NON-NLS-1$
text.setFont(JFaceResources.getDefaultFont());
GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
gridData.minimumHeight = 22;
String author = comment.getAuthor() + " : "; //$NON-NLS-1$
String commentContent = comment.getContent();
IDocument contentDocument = new Document(author + commentContent);
setDocument(contentDocument);
styleRange = new StyleRange();
styleRange.start = 0;
styleRange.length = author.lastIndexOf(':');
styleRange.foreground = null;
styleRange.background = null;
styleRange.fontStyle = SWT.BOLD;
text.setStyleRange(styleRange);
ScrolledComposite sc = container.getScrolledComposite();
if (sc.getClientArea().width != 0) {
gridData.widthHint = sc.getClientArea().width - EXTRA_WIDTH;
}
text.setLayoutData(gridData);
sc.addControlListener(getControlListener());
text.addModifyListener(getModifyListener());
text.addFocusListener(getFocusListener());
}
private void createTimeLabel(Composite parent) {
timeLabel = new Label(parent, SWT.NONE);
timeLabel.setAlignment(SWT.LEFT);
timeLabel.setBackground(parent.getBackground());
timeLabel.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#999999"))); //$NON-NLS-1$
timeLabel.setFont((Font) resources.get(
JFaceResources.getDefaultFontDescriptor().increaseHeight(-1)));
GridData layoutData = new GridData(SWT.FILL, SWT.TOP, true, false);
layoutData.horizontalIndent = 3;
layoutData.verticalIndent = 0;
timeLabel.setLayoutData(layoutData);
if (comment != container.getLatestCreatedComment()) {
long timeMillisString = comment.getTime();
String dateString = TextFormatter.formatTimeMillis(timeMillisString,
CommentsConstants.DATE_FORMAT_PATTERN);
String timeString = TextFormatter.formatTimeMillis(timeMillisString,
CommentsConstants.TIME_FORMAT_PATTERN);
timeLabel.setText(dateString + " at " + timeString); //$NON-NLS-1$
} else {
container.setLatestCreatedComment(null);
timeLabel.setText(MindMapMessages.Comment_JustNow_text);
}
}
private void createModifyCommentActionBar(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridData layoutData = new GridData(GridData.FILL_HORIZONTAL);
layoutData.verticalIndent = 5;
composite.setLayoutData(layoutData);
composite.setBackground(parent.getBackground());
GridLayout layout = new GridLayout(2, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
composite.setLayout(layout);
IAction cancelModifyAction = new Action() {
@Override
public void run() {
cancelEditing();
}
};
Hyperlink cancelLink = createLink(composite,
MindMapMessages.Comment_Cancel_text,
MindMapMessages.Comment_Cancel_tooltip, cancelModifyAction);
cancelLink.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false));
IAction modifyCommentAction = new Action() {
@Override
public void run() {
saveComment();
}
};
Hyperlink addLink = createLink(composite,
MindMapMessages.ModifyComment_text,
MindMapMessages.ModifyComment_tooltip, modifyCommentAction);
addLink.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, true, false));
modifyCommentActionBar = composite;
}
//recursion add contextMenu
private void addContextMenu() {
setRecursionContextMenu(control, getContextMenu());
}
//recursion remove contextMenu
private void removeContextMenu() {
setRecursionContextMenu(control, null);
}
private void setRecursionContextMenu(Control control, Menu contextMenu) {
if (control != null && !control.isDisposed()) {
control.setMenu(contextMenu);
}
if (control instanceof Composite) {
Control[] children = ((Composite) control).getChildren();
for (Control child : children) {
setRecursionContextMenu(child, contextMenu);
}
}
}
private Menu getContextMenu() {
if (contextMenu == null || contextMenu.isDisposed()) {
MenuManager menuManager = new MenuManager();
menuManager.add(new Action(MindMapMessages.Comment_Edit_label) {
@Override
public void run() {
startEditing();
}
});
menuManager.add(new Action(MindMapMessages.Comment_Delete_label) {
@Override
public void run() {
DeleteCommentCommand cmd = new DeleteCommentCommand(
comment.getOwnedWorkbook().getElementById(
comment.getObjectId()),
comment);
ICommandStack cs = targetEditor.getCommandStack();
cs.execute(cmd);
}
});
menuManager.add(new Action(MindMapMessages.Comment_Reply_label) {
@Override
public void run() {
container.createComment(comment.getObjectId());
}
});
contextMenu = menuManager.createContextMenu(control.getShell());
}
return contextMenu;
}
private TextViewer createTextViewer(Composite parent, int style) {
return new LessLatencyTextViewer(parent, style);
}
private void initTextViewer(TextViewer textViewer) {
Control control = textViewer.getTextWidget();
createContentPopupMenu(control);
textViewer.setTextDoubleClickStrategy(
new DefaultTextDoubleClickStrategy(),
IDocument.DEFAULT_CONTENT_TYPE);
textViewer.setUndoManager(new TextViewerUndoManager(25));
textViewer.activatePlugins();
addHyperlinkListener(textViewer);
}
private void createContentPopupMenu(Control control) {
textContextMenuManager = new MenuManager();
textContextMenuManager.setRemoveAllWhenShown(true);
textContextMenuManager.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
fillContextMenu(manager);
}
});
textContextMenu = textContextMenuManager.createContextMenu(control);
control.setMenu(textContextMenu);
}
private void fillContextMenu(IMenuManager menu) {
if (contributor != null)
contributor.fillContextMenu(menu);
}
private void addHyperlinkListener(TextViewer viewer) {
PresentationReconciler reconciler = new PresentationReconciler();
RichTextDamagerRepairer dr = new RichTextDamagerRepairer(
new RichTextScanner());
reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setDocumentPartitioning(
IDocumentExtension3.DEFAULT_PARTITIONING);
reconciler.install(viewer);
}
private void addMouseFilter() {
Display.getCurrent().addFilter(SWT.MouseEnter, getListener());
Display.getCurrent().addFilter(SWT.MouseExit, getListener());
}
private void removeMouseFilter() {
Display.getCurrent().removeFilter(SWT.MouseEnter, getListener());
Display.getCurrent().removeFilter(SWT.MouseExit, getListener());
}
private Listener getListener() {
if (listener == null) {
listener = new Listener() {
public void handleEvent(Event event) {
if (control.isDisposed()) {
removeMouseFilter();
return;
}
if (event.widget instanceof Control) {
boolean isAncestor = isAncestorOf((Composite) control,
(Control) event.widget);
switch (event.type) {
case SWT.MouseEnter:
if (isAncestor) {
setRecursiveBackgroundColor(control, hoverColor,
null);
control.layout();
}
break;
case SWT.MouseExit:
if (!isAncestor) {
if (textViewer.getTextWidget()
.isFocusControl()) {
setRecursiveBackgroundColor(control,
originalColor, getTextWidget());
} else {
setRecursiveBackgroundColor(control,
originalColor, null);
}
control.layout();
}
break;
}
}
}
};
}
return listener;
}
private boolean isAncestorOf(Control composite, Control control) {
if (control == composite) {
return true;
}
Composite parent = control.getParent();
while (parent != null && parent != composite
&& !(parent instanceof Shell)) {
parent = parent.getParent();
}
return parent == composite;
}
private void setRecursiveBackgroundColor(Control control, Color background,
Control excludeControl) {
if (control == excludeControl) {
return;
}
control.setBackground(background);
if (control instanceof Composite) {
Control[] children = ((Composite) control).getChildren();
for (Control child : children) {
setRecursiveBackgroundColor(child, background, excludeControl);
}
}
}
private MouseListener getMouseListener() {
if (mouseListener == null) {
mouseListener = new MouseAdapter() {
public void mouseDown(MouseEvent e) {
if (getSelection() instanceof IStructuredSelection
&& ((IStructuredSelection) getSelection())
.getFirstElement() == CommentTextViewer.this) {
if (e.button == 1) {
selectionProvider.removeSelectionChangedListener(
getSelectionChangedListener());
setSelection(null);
selectionProvider.addSelectionChangedListener(
getSelectionChangedListener());
startEditing();
}
} else {
setSelection(new StructuredSelection(
CommentTextViewer.this));
}
}
};
}
return mouseListener;
}
private ISelectionChangedListener getSelectionChangedListener() {
if (selectionChangedListener == null) {
selectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
ISelection oldSelection = ((CommentsSelectionProvider) selectionProvider)
.getOldSelection();
if (oldSelection instanceof IStructuredSelection) {
Object obj = ((IStructuredSelection) oldSelection)
.getFirstElement();
if (obj == CommentTextViewer.this
&& !getTextWidget().isFocusControl()) {
((CommentTextViewer) obj).commentDeselected();
}
}
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection) {
Object obj = ((IStructuredSelection) selection)
.getFirstElement();
if (obj == CommentTextViewer.this) {
commentSelected();
}
}
}
};
}
return selectionChangedListener;
}
private void commentSelected() {
// if (container instanceof CommentsView) {
// CommentsUtils.reveal(targetEditor, comment.getOwnedWorkbook()
// .getElementById(comment.getObjectId()));
// }
removeMouseFilter();
setRecursiveBackgroundColor(control, selectColor, null);
container.getContentComposite().pack();
container.getContentComposite().layout(true, true);
}
private void commentDeselected() {
addMouseFilter();
if (textViewer.getTextWidget().isFocusControl()) {
setRecursiveBackgroundColor(control, originalColor,
getTextWidget());
} else {
setRecursiveBackgroundColor(control, originalColor, null);
}
container.getContentComposite().pack();
container.getContentComposite().layout(true, true);
}
private FocusListener getFocusListener() {
if (textFocusListener == null) {
textFocusListener = new FocusListener() {
public void focusGained(FocusEvent e) {
textViewer.getTextWidget().setBackground(
e.display.getSystemColor(SWT.COLOR_WHITE));
getTextWidget().addCaretListener(getCaretListener());
getTextViewer().addTextListener(getTextListener());
getTextViewer().addPostSelectionChangedListener(
getPostSelectionChangedListener());
addSpellChecker(textViewer);
showControl();
updateActions();
container.setSelectedComment(comment);
}
public void focusLost(FocusEvent e) {
textViewer.getTextWidget().setBackground(originalColor);
getTextWidget().removeCaretListener(getCaretListener());
getTextViewer().removePostSelectionChangedListener(
getPostSelectionChangedListener());
setEditable(false);
removeSpellChecker();
container.setSelectedComment(null);
if (!isLinkHovering) {
if (comment == null) {
addComment();
container.setModified(true);
} else {
boolean modified = saveComment();
container.setModified(modified);
}
}
}
};
}
return textFocusListener;
}
private void startEditing() {
container.getContentComposite().forceFocus();
//store last editing.
if (container.isModified()) {
container.setModified(false);
container.setEditingComment(comment);
return;
}
if (control.isDisposed()) {
return;
}
removeMouseFilter();
setRecursiveBackgroundColor(control, originalColor, null);
getTextWidget().setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#000000"))); //$NON-NLS-1$
getTextWidget().getParent().setBackground(
(Color) resources.get(ColorUtils.toDescriptor("#298fca"))); //$NON-NLS-1$
CommentsUtils.removeRecursiveMouseListener(control, getMouseListener(),
null);
removeContextMenu();
textViewer.getControl().setMenu(textContextMenu);
textViewer.getTextWidget().setStyleRange(null);
String commentContent = comment.getContent();
IDocument contentDocument = new Document(commentContent);
setDocument(contentDocument);
timeLabel.setVisible(false);
((GridData) timeLabel.getLayoutData()).exclude = true;
modifyCommentActionBar.setVisible(true);
((GridData) modifyCommentActionBar.getLayoutData()).exclude = false;
((GridData) textViewer.getControl()
.getLayoutData()).minimumHeight = 110;
setEditable(true);
textViewer.getControl().setFocus();
container.getContentComposite().pack();
container.getContentComposite().layout(true, true);
}
private void cancelEditing() {
setRecursiveBackgroundColor(control, originalColor, null);
getTextWidget().setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#45464a"))); //$NON-NLS-1$
CommentsUtils.addRecursiveMouseListener(control, getMouseListener(),
null);
addContextMenu();
String author = comment.getAuthor() + " : "; //$NON-NLS-1$
String commentContent = comment.getContent();
IDocument contentDocument = new Document(author + commentContent);
setDocument(contentDocument);
textViewer.getTextWidget().setStyleRange(styleRange);
resetModified();
timeLabel.setVisible(true);
((GridData) timeLabel.getLayoutData()).exclude = false;
modifyCommentActionBar.setVisible(false);
((GridData) modifyCommentActionBar.getLayoutData()).exclude = true;
((GridData) textViewer.getControl().getLayoutData()).minimumHeight = 22;
setEditable(false);
addMouseFilter();
if (container != null && container.getContentComposite() != null
&& !container.getContentComposite().isDisposed()) {
container.getContentComposite().pack();
container.getContentComposite().layout(true, true);
}
}
private void showControl() {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
if (!container.getScrolledComposite().isDisposed()
&& !control.isDisposed()) {
container.getScrolledComposite().showControl(control);
}
}
});
}
private void updateActions() {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
if (control.isDisposed() || getTextWidget().isDisposed()) {
return;
}
IComment selectedComment = (control.isFocusControl()
|| getTextWidget().isFocusControl()) ? comment : null;
contributor.selectedCommentChanged(selectedComment);
}
});
}
private void addSpellChecker(ITextViewer textViewer) {
spellingActivation = SpellingSupport.getInstance()
.activateSpelling(textViewer);
spellingPreferences = SpellingPlugin.getDefault().getPreferenceStore();
if (spellingPreferences != null) {
spellingPreferences
.addPropertyChangeListener(getPropertyChangeListener());
}
contributor.setSpellingActivation(spellingActivation);
}
private void removeSpellChecker() {
if (spellingPreferences != null) {
spellingPreferences
.removePropertyChangeListener(getPropertyChangeListener());
spellingPreferences = null;
}
if (spellingActivation != null) {
spellingActivation.getSpellingSupport()
.deactivateSpelling(spellingActivation);
spellingActivation = null;
}
}
//for SpellChecker
private IPropertyChangeListener getPropertyChangeListener() {
if (propertyChangeListener == null) {
propertyChangeListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if (SpellingPlugin.SPELLING_CHECK_ENABLED
.equals(event.getProperty())) {
if (spellingActivation != null) {
spellingActivation.getSpellingSupport()
.deactivateSpelling(spellingActivation);
spellingActivation = null;
}
if (spellingPreferences.getBoolean(
SpellingPlugin.SPELLING_CHECK_ENABLED)) {
spellingActivation = SpellingSupport.getInstance()
.activateSpelling(textViewer);
}
}
}
};
}
return propertyChangeListener;
}
//sc.setNewOrigin when caret move(editing)
private CaretListener getCaretListener() {
if (caretListener == null) {
caretListener = new CaretListener() {
public void caretMoved(CaretEvent event) {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
if (getTextWidget() == null
|| getTextWidget().isDisposed()) {
return;
}
Caret caret = getTextWidget().getCaret();
ScrolledComposite sc = container
.getScrolledComposite();
Rectangle caretBounds = caret.getBounds();
Rectangle scClientArea = sc.getClientArea();
int caretToDisplayY = getTextWidget()
.toDisplay(caret.getLocation()).y;
Point scToDisplayPoint = sc.getParent()
.toDisplay(sc.getLocation());
int scToDisplayY = scToDisplayPoint.y;
Point scOrigin = sc.getOrigin();
if (caretToDisplayY
+ caretBounds.height > scToDisplayY
+ scClientArea.height) {
scOrigin.y += (caretToDisplayY
+ caretBounds.height)
- (scToDisplayY + scClientArea.height);
sc.setOrigin(scOrigin);
} else if (caretToDisplayY < scToDisplayY) {
scOrigin.y -= scToDisplayY - caretToDisplayY;
sc.setOrigin(scOrigin);
}
}
});
}
};
}
return caretListener;
}
//update text popup menus' selection
private ISelectionChangedListener getPostSelectionChangedListener() {
if (postSelectionChangedListener == null) {
postSelectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
contributor.update(textViewer);
}
};
}
return postSelectionChangedListener;
}
//set text.widthHint -- then pack in CommentsView / CommentsPopup.
private ControlListener getControlListener() {
if (controlListener == null) {
controlListener = new ControlListener() {
public void controlMoved(ControlEvent e) {
}
public void controlResized(ControlEvent e) {
if (container == null
|| container.getContentComposite().isDisposed()) {
return;
}
Composite contentComposite = container
.getContentComposite();
StyledText text = getTextWidget();
if (text != null && !text.isDisposed()) {
((GridData) text
.getLayoutData()).widthHint = contentComposite
.getParent().getClientArea().width
- EXTRA_WIDTH;
}
}
};
}
return controlListener;
}
//register Core.WorkbookPreSaveOnce when editing -- make workbook dirty.
private ITextListener getTextListener() {
if (textListener == null) {
textListener = new ITextListener() {
public void textChanged(
org.eclipse.jface.text.TextEvent event) {
activateJob();
}
};
}
return textListener;
}
//pack contentComposite when styledText be modified.
private ModifyListener getModifyListener() {
if (modifyListener == null) {
modifyListener = new ModifyListener() {
public void modifyText(ModifyEvent event) {
Composite contentComposite = container
.getContentComposite();
int realTextlHeight = contentComposite
.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
if (textHeight != realTextlHeight) {
textHeight = realTextlHeight;
contentComposite.pack();
}
}
};
}
return modifyListener;
}
private void activateJob() {
if (saveCommentReg != null && saveCommentReg.isValid()) {
return;
}
saveCommentReg = null;
if (workbook instanceof ICoreEventSource2) {
saveCommentReg = ((ICoreEventSource2) workbook)
.registerOnceCoreEventListener(Core.WorkbookPreSaveOnce,
ICoreEventListener.NULL);
}
}
private void deactivateJob() {
if (saveCommentReg != null) {
saveCommentReg.unregister();
saveCommentReg = null;
}
}
private void resetModified() {
deactivateJob();
getTextViewer().removeTextListener(getTextListener());
}
private void handleControlDispose(DisposeEvent e) {
if (textContextMenuManager != null) {
textContextMenuManager.dispose();
textContextMenuManager = null;
}
if (textContextMenu != null) {
textContextMenu.dispose();
textContextMenu = null;
}
if (contextMenu != null) {
contextMenu.dispose();
contextMenu = null;
}
if (document != null) {
document = null;
}
removeMouseFilter();
getTextWidget().removeFocusListener(getFocusListener());
ScrolledComposite sc = container.getScrolledComposite();
if (sc != null && !sc.isDisposed()) {
sc.removeControlListener(getControlListener());
}
if (selectionProvider != null) {
selectionProvider.removeSelectionChangedListener(
getSelectionChangedListener());
}
getTextWidget().removeModifyListener(getModifyListener());
}
private boolean addComment() {
resetModified();
isLinkHovering = false;
final IDocument document = (IDocument) textViewer.getInput();
if (document == null || document.get() == null
|| document.get().equals("")) { //$NON-NLS-1$
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
container.cancelCreateComment();
}
});
return false;
}
String author = System.getProperty(DOMConstants.AUTHOR_NAME);
author = (author != null ? author : System.getProperty("user.name")); //$NON-NLS-1$
long time = System.currentTimeMillis();
IComment comment = workbook.getCommentManager().createComment(author,
time, objectId);
final AddCommentCommand cmd = new AddCommentCommand(author, time,
objectId, document.get(), workbook, comment);
container.setLatestCreatedComment(comment);
final ICommandStack cs = targetEditor.getCommandStack();
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
cs.execute(cmd);
}
});
return true;
}
private boolean saveComment() {
resetModified();
isLinkHovering = false;
String oldContent = (comment == null ? null : comment.getContent());
IDocument document = (IDocument) textViewer.getDocument();
String newContent = document.get();
if (newContent != null && newContent.equals(oldContent)) {
cancelEditing();
return false;
}
final ICommandStack cs = targetEditor.getCommandStack();
Command command = null;
if (document == null || document.get() == null
|| document.get().equals("")) { //$NON-NLS-1$
command = new DeleteCommentCommand(comment.getOwnedWorkbook()
.getElementById(comment.getObjectId()), comment);
} else {
command = new ModifyCommentCommand(comment.getOwnedWorkbook()
.getElementById(comment.getObjectId()), comment,
document.get());
}
final Command command_0 = command;
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
cs.execute(command_0);
}
});
return true;
}
private void setEditable(boolean editable) {
if (editable == this.editable) {
return;
}
this.editable = editable;
updateTextControl();
}
private void setDocument(IDocument document) {
this.document = document;
textViewer.setDocument(document == null ? new Document() : document);
updateTextControl();
// move the caret to the end of document
if (document != null) {
textViewer.setSelectedRange(document.getLength(), 0);
}
}
private void updateTextControl() {
textViewer.setEditable(editable);
if (textViewer.getTextWidget() != null
&& !textViewer.getTextWidget().isDisposed()) {
textViewer.getTextWidget().setEnabled(editable);
}
}
public TextViewer getTextViewer() {
return textViewer;
}
private StyledText getTextWidget() {
return textViewer.getTextWidget();
}
private ISelection getSelection() {
return selectionProvider.getSelection();
}
private void setSelection(ISelection selection) {
selectionProvider.setSelection(selection);
}
public void setTargetEditor(IGraphicalEditor targetEditor) {
this.targetEditor = targetEditor;
}
}