blob: 873398ba74b64e88e8860a4c6cf4eae46f0eaa3d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2015 Tasktop Technologies and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Tasktop Technologies - initial API and implementation
* Jingwen Ou - comment grouping
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.ui.editors;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.mylyn.commons.ui.CommonImages;
import org.eclipse.mylyn.commons.ui.FillWidthLayout;
import org.eclipse.mylyn.commons.ui.SelectionProviderAdapter;
import org.eclipse.mylyn.commons.ui.compatibility.CommonColors;
import org.eclipse.mylyn.commons.workbench.forms.CommonFormUtil;
import org.eclipse.mylyn.commons.workbench.forms.ScalingHyperlink;
import org.eclipse.mylyn.internal.tasks.core.TaskComment;
import org.eclipse.mylyn.internal.tasks.ui.actions.CommentActionGroup;
import org.eclipse.mylyn.internal.tasks.ui.editors.CommentGroupStrategy.CommentGroup;
import org.eclipse.mylyn.tasks.core.IRepositoryPerson;
import org.eclipse.mylyn.tasks.core.ITaskComment;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskDataModel;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor;
import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.Section;
import com.google.common.base.Strings;
/**
* @author Robert Elves
* @author Steffen Pingel
* @author Jingwen Ou
*/
public class TaskEditorCommentPart extends AbstractTaskEditorPart {
private static final String ID_POPUP_MENU = "org.eclipse.mylyn.tasks.ui.editor.menu.comments"; //$NON-NLS-1$
public class CommentGroupViewer {
private final CommentGroup commentGroup;
private ArrayList<CommentViewer> commentViewers;
private Section groupSection;
private boolean renderedInSubSection;
public CommentGroupViewer(CommentGroup commentGroup) {
this.commentGroup = commentGroup;
}
private Composite createCommentViewers(Composite parent, FormToolkit toolkit) {
List<CommentViewer> viewers = getCommentViewers();
Composite composite = toolkit.createComposite(parent);
GridLayout contentLayout = new GridLayout();
contentLayout.marginHeight = 0;
contentLayout.marginWidth = 0;
composite.setLayout(contentLayout);
for (CommentViewer commentViewer : viewers) {
Control control = commentViewer.createControl(composite, toolkit);
GridDataFactory.fillDefaults().grab(true, false).applyTo(control);
}
return composite;
}
private Control createControl(Composite parent, FormToolkit toolkit) {
if (renderedInSubSection) {
return createSection(parent, toolkit);
} else {
if (TaskEditorCommentPart.this.commentAttributes.size() >= CommentGroupStrategy.MAX_CURRENT) {
// show a separator before current comments
Canvas separator = new Canvas(parent, SWT.NONE) {
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
return new Point((wHint == SWT.DEFAULT) ? 1 : wHint, 1);
}
};
separator.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
e.gc.setForeground(separator.getForeground());
e.gc.drawLine(0, 0, separator.getSize().x, 0);
}
});
separator.setForeground(toolkit.getColors().getColor(IFormColors.TB_BORDER));
GridDataFactory.fillDefaults().grab(true, false).indent(2 * INDENT, 0).applyTo(separator);
}
return createCommentViewers(parent, toolkit);
}
}
private Section createSection(Composite parent, FormToolkit toolkit) {
int style = ExpandableComposite.TWISTIE | ExpandableComposite.SHORT_TITLE_BAR
| ExpandableComposite.LEFT_TEXT_CLIENT_ALIGNMENT;
groupSection = toolkit.createSection(parent, style);
groupSection.clientVerticalSpacing = 0;
if (commentGroup.hasIncoming()) {
groupSection.setBackground(getTaskEditorPage().getAttributeEditorToolkit().getColorIncoming());
}
groupSection.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
groupSection.setText(commentGroup.getGroupName() + Messages.TaskEditorCommentPart_0
+ commentGroup.getCommentAttributes().size() + Messages.TaskEditorCommentPart_1);
if (groupSection.isExpanded()) {
Composite composite = createCommentViewers(groupSection, toolkit);
groupSection.setClient(composite);
} else {
groupSection.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent e) {
if (commentGroup.hasIncoming()) {
if (e.getState()) {
groupSection.setBackground(null);
} else {
// only decorate background with incoming color when collapsed, otherwise
// there is too much decoration in the editor
groupSection.setBackground(
getTaskEditorPage().getAttributeEditorToolkit().getColorIncoming());
}
}
if (groupSection.getClient() == null) {
try {
getTaskEditorPage().setReflow(false);
Composite composite = createCommentViewers(groupSection, toolkit);
groupSection.setClient(composite);
} finally {
getTaskEditorPage().setReflow(true);
}
reflow();
}
}
});
}
return groupSection;
}
public List<CommentViewer> getCommentViewers() {
if (commentViewers != null) {
return commentViewers;
}
commentViewers = new ArrayList<CommentViewer>(commentGroup.getCommentAttributes().size());
for (TaskAttribute commentAttribute : commentGroup.getCommentAttributes()) {
CommentViewer commentViewer = new CommentViewer(commentAttribute);
commentViewers.add(commentViewer);
}
return commentViewers;
}
public boolean isExpanded() {
if (groupSection != null) {
return groupSection.isExpanded();
}
if (commentViewers != null) {
for (CommentViewer commentViewer : commentViewers) {
if (commentViewer.isExpanded()) {
return true;
}
}
}
return false;
}
/**
* Returns true if this group and all comments in it are expanded.
*/
public boolean isFullyExpanded() {
if (groupSection != null && !groupSection.isExpanded()) {
return false;
}
if (commentViewers != null) {
for (CommentViewer commentViewer : commentViewers) {
if (!commentViewer.isExpanded()) {
return false;
}
}
return true;
}
return false;
}
public boolean isRenderedInSubSection() {
return renderedInSubSection;
}
public void setExpanded(boolean expanded) {
if (groupSection != null && groupSection.isExpanded() != expanded) {
CommonFormUtil.setExpanded(groupSection, expanded);
}
}
/**
* Expands this group and all comments in it.
*/
public void setFullyExpanded(boolean expanded) {
if (groupSection != null && groupSection.isExpanded() != expanded) {
CommonFormUtil.setExpanded(groupSection, expanded);
}
if (commentViewers != null) {
for (CommentViewer commentViewer : commentViewers) {
commentViewer.setExpanded(expanded);
}
}
}
public void setRenderedInSubSection(boolean renderedInSubSection) {
this.renderedInSubSection = renderedInSubSection;
}
public void createSectionHyperlink(String message, HyperlinkAdapter listener) {
if (groupSection != null) {
ScalingHyperlink resultLink = new ScalingHyperlink(groupSection, SWT.READ_ONLY);
resultLink.setForeground(CommonColors.HYPERLINK_WIDGET);
resultLink.setUnderlined(true);
resultLink.setText(message);
groupSection.setTextClient(resultLink);
resultLink.getParent().layout(true, true);
resultLink.addHyperlinkListener(listener);
}
}
public void clearSectionHyperlink() {
if (groupSection != null) {
groupSection.setTextClient(null);
}
}
}
public class CommentViewer {
private Composite buttonComposite;
private final TaskAttribute commentAttribute;
private ExpandableComposite commentComposite;
private final TaskComment taskComment;
private Composite commentViewer;
private Composite userImageComposite;
private AbstractAttributeEditor commentTextEditor;
private boolean suppressSelectionChanged;
public CommentViewer(TaskAttribute commentAttribute) {
this.commentAttribute = commentAttribute;
this.taskComment = new TaskComment(getModel().getTaskRepository(), getModel().getTask(), commentAttribute);
}
public Control createControl(Composite composite, FormToolkit toolkit) {
boolean hasIncomingChanges = getModel().hasIncomingChanges(commentAttribute);
getTaskData().getAttributeMapper().updateTaskComment(taskComment, commentAttribute);
int style = ExpandableComposite.TREE_NODE | ExpandableComposite.LEFT_TEXT_CLIENT_ALIGNMENT
| ExpandableComposite.COMPACT;
if (hasIncomingChanges || (expandAllInProgress && !suppressExpandViewers)) {
style |= ExpandableComposite.EXPANDED;
}
commentComposite = toolkit.createExpandableComposite(composite, style);
commentComposite.clientVerticalSpacing = 0;
commentComposite.setLayout(new GridLayout());
commentComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
commentComposite.setTitleBarForeground(toolkit.getColors().getColor(IFormColors.TITLE));
buttonComposite = createTitle(commentComposite, toolkit);
Composite commentViewerComposite = toolkit.createComposite(commentComposite);
commentComposite.setClient(commentViewerComposite);
commentViewerComposite
.setLayout(new FillWidthLayout(EditorUtil.getLayoutAdvisor(getTaskEditorPage()), 15, 0, 0, 3));
commentComposite.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent event) {
expandComment(toolkit, commentViewerComposite, event.getState());
}
});
if (hasIncomingChanges) {
commentComposite.setBackground(getTaskEditorPage().getAttributeEditorToolkit().getColorIncoming());
}
if (commentComposite.isExpanded()) {
expandComment(toolkit, commentViewerComposite, true);
}
// for outline
EditorUtil.setMarker(commentComposite, commentAttribute.getId());
return commentComposite;
}
private Composite createTitle(ExpandableComposite commentComposite, FormToolkit toolkit) {
// always visible
Composite titleComposite = toolkit.createComposite(commentComposite);
commentComposite.setTextClient(titleComposite);
RowLayout rowLayout = new RowLayout();
rowLayout.pack = true;
rowLayout.marginLeft = 0;
rowLayout.marginBottom = 0;
rowLayout.marginTop = 0;
rowLayout.center = true;
titleComposite.setLayout(rowLayout);
titleComposite.setBackground(null);
ImageHyperlink expandCommentHyperlink = createTitleHyperLink(toolkit, titleComposite, taskComment);
expandCommentHyperlink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
CommonFormUtil.setExpanded(commentComposite, !commentComposite.isExpanded());
}
});
ToolBarManager toolBarManagerTitle = new ToolBarManager(SWT.FLAT);
addActionsToToolbarTitle(toolBarManagerTitle, taskComment, this);
toolBarManagerTitle.createControl(titleComposite);
// only visible when section is expanded
Composite buttonComposite = toolkit.createComposite(titleComposite);
RowLayout buttonCompLayout = new RowLayout();
buttonCompLayout.marginBottom = 0;
buttonCompLayout.marginTop = 0;
buttonComposite.setLayout(buttonCompLayout);
buttonComposite.setBackground(null);
buttonComposite.setVisible(commentComposite.isExpanded());
ToolBarManager toolBarManagerButton = new ToolBarManager(SWT.FLAT);
addActionsToToolbarButton(toolBarManagerButton, taskComment, this);
toolBarManagerButton.createControl(buttonComposite);
return buttonComposite;
}
private ImageHyperlink createTitleHyperLink(FormToolkit toolkit, Composite toolbarComp,
ITaskComment taskComment) {
ImageHyperlink formHyperlink = toolkit.createImageHyperlink(toolbarComp, SWT.NONE);
formHyperlink.setBackground(null);
formHyperlink.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
IRepositoryPerson author = taskComment.getAuthor();
if (author != null && author.matchesUsername(getTaskEditorPage().getTaskRepository().getUserName())) {
formHyperlink.setImage(CommonImages.getImage(CommonImages.PERSON_ME_NARROW));
} else {
formHyperlink.setImage(CommonImages.getImage(CommonImages.PERSON_NARROW));
}
StringBuilder sb = new StringBuilder();
if (taskComment.getNumber() >= 0) {
sb.append(taskComment.getNumber());
sb.append(": "); //$NON-NLS-1$
}
String toolTipText = ""; //$NON-NLS-1$;
if (author != null) {
if (author.getName() != null) {
sb.append(author.getName());
toolTipText = author.getPersonId();
} else {
sb.append(author.getPersonId());
}
}
if (taskComment.getCreationDate() != null) {
sb.append(", "); //$NON-NLS-1$
sb.append(EditorUtil.formatDateTime(taskComment.getCreationDate()));
}
formHyperlink.setFont(commentComposite.getFont());
formHyperlink.setToolTipText(toolTipText);
formHyperlink.setText(sb.toString());
formHyperlink.setEnabled(true);
formHyperlink.setUnderlined(false);
return formHyperlink;
}
private void expandComment(FormToolkit toolkit, Composite composite, boolean expanded) {
buttonComposite.setVisible(expanded);
if (expanded && composite.getData(KEY_EDITOR) == null) {
commentViewer = toolkit.createComposite(composite);
commentViewer.setLayout(new GridLayout(2, false));
commentViewer.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
//Create user image viewer
boolean showAvatar = Boolean.parseBoolean(getModel().getTaskRepository()
.getProperty(TaskEditorExtensions.REPOSITORY_PROPERTY_AVATAR_SUPPORT));
if (showAvatar) {
String commentAuthor = getTaskData().getAttributeMapper().mapToRepositoryKey(commentAttribute,
TaskAttribute.COMMENT_AUTHOR);
TaskAttribute userImageAttribute = commentAttribute.getAttribute(commentAuthor);
if (userImageAttribute != null) {
userImageComposite = toolkit.createComposite(commentViewer);
userImageComposite.setLayout(new GridLayout(1, false));
GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.BEGINNING).applyTo(userImageComposite);
toolkit.paintBordersFor(userImageComposite);
UserAttributeEditor userImage = new UserAttributeEditor(getModel(), userImageAttribute, 30);
userImage.createControl(userImageComposite, toolkit);
userImage.refresh();
}
}
//Create comment text viewer
TaskAttribute textAttribute = getTaskData().getAttributeMapper()
.getAssoctiatedAttribute(taskComment.getTaskAttribute());
commentTextEditor = createAttributeEditor(textAttribute);
if (commentTextEditor != null) {
commentTextEditor.setDecorationEnabled(false);
commentTextEditor.createControl(commentViewer, toolkit);
GridData commentGridData = new GridData(GridData.FILL_HORIZONTAL);
commentGridData.verticalAlignment = GridData.BEGINNING;
commentTextEditor.getControl().setLayoutData(commentGridData);
commentTextEditor.getControl().addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
getTaskEditorPage().selectionChanged(taskComment);
}
});
composite.setData(KEY_EDITOR, commentTextEditor);
getTaskEditorPage().getAttributeEditorToolkit().adapt(commentTextEditor);
reflow();
}
} else if (!expanded && composite.getData(KEY_EDITOR) != null) {
// dispose viewer
commentTextEditor.getControl().setMenu(null);
commentTextEditor.getControl().dispose();
if (userImageComposite != null) {
userImageComposite.setMenu(null);
userImageComposite.dispose();
}
if (commentViewer != null) {
commentViewer.setMenu(null);
commentViewer.dispose();
}
composite.setData(KEY_EDITOR, null);
reflow();
}
if (!suppressSelectionChanged) {
getTaskEditorPage().selectionChanged(taskComment);
}
}
public boolean isExpanded() {
return commentComposite != null && commentComposite.isExpanded();
}
public void setExpanded(boolean expanded) {
if (commentComposite != null && commentComposite.isExpanded() != expanded) {
CommonFormUtil.setExpanded(commentComposite, expanded);
}
}
/**
* Returns the comment viewer.
*
* @return null, if the viewer has not been constructed
*/
public AbstractAttributeEditor getEditor() {
return commentTextEditor;
}
public TaskAttribute getTaskAttribute() {
return commentAttribute;
}
public TaskComment getTaskComment() {
return taskComment;
}
public Control getControl() {
return commentComposite;
}
public void suppressSelectionChanged(boolean value) {
this.suppressSelectionChanged = value;
}
public String getReplyToText() {
String replyText = taskComment.getText();
if (hasTextControl()) {
Control textControl = commentTextEditor.getControl();
String selectedText = getSelectedText(textControl);
if (!Strings.isNullOrEmpty(selectedText)) {
replyText = selectedText;
}
}
return replyText;
}
private String getSelectedText(Control control) {
if (control instanceof StyledText) {
return ((StyledText) control).getSelectionText();
} else if (control instanceof Composite) {
for (Control child : ((Composite) control).getChildren()) {
String selectedText = getSelectedText(child);
if (!Strings.isNullOrEmpty(selectedText)) {
return selectedText;
}
}
}
return null;
}
private boolean hasTextControl() {
return commentTextEditor != null && commentTextEditor.getControl() != null
&& !commentTextEditor.getControl().isDisposed();
}
}
private class ReplyToCommentAction extends AbstractReplyToCommentAction {
private final CommentViewer commentViewer;
public ReplyToCommentAction(CommentViewer commentViewer) {
super(TaskEditorCommentPart.this.getTaskEditorPage(), commentViewer.getTaskComment());
this.commentViewer = commentViewer;
}
@Override
protected String getReplyText() {
return commentViewer.getReplyToText();
}
protected CommentViewer getCommentViewer() {
return commentViewer;
}
public void dispose() {
}
}
private class ReplyToCommentActionWithMenu extends ReplyToCommentAction implements IMenuCreator {
public ReplyToCommentActionWithMenu(CommentViewer commentViewer) {
super(commentViewer);
setMenuCreator(this);
}
public Menu getMenu(Control parent) {
currentViewer = getCommentViewer();
selectionProvider.setSelection(new StructuredSelection(currentViewer.getTaskComment()));
return commentMenu;
}
public Menu getMenu(Menu parent) {
selectionProvider.setSelection(new StructuredSelection(getCommentViewer().getTaskComment()));
return commentMenu;
}
}
/** Expandable composites are indented by 6 pixels by default. */
private static final int INDENT = -6;
private static final String KEY_EDITOR = "viewer"; //$NON-NLS-1$
private List<TaskAttribute> commentAttributes;
private CommentGroupStrategy commentGroupStrategy;
private List<CommentGroupViewer> commentGroupViewers;
private boolean expandAllInProgress;
private boolean hasIncoming;
/**
* We can't use the reflow flag in AbstractTaskEditorPage because it gets set at various points where we might not
* want to reflow.
*/
private boolean reflow = true;
protected Section section;
private SelectionProviderAdapter selectionProvider;
// XXX: stores a reference to the viewer for which the commentMenu was displayed last
private CommentViewer currentViewer;
private Menu commentMenu;
private CommentActionGroup actionGroup;
private boolean suppressExpandViewers;
public TaskEditorCommentPart() {
this.commentGroupStrategy = new CommentGroupStrategy() {
@Override
protected boolean hasIncomingChanges(ITaskComment taskComment) {
return getModel().hasIncomingChanges(taskComment.getTaskAttribute());
}
};
setPartName(Messages.TaskEditorCommentPart_Comments);
}
protected void addActionsToToolbarButton(ToolBarManager toolBarManager, TaskComment taskComment,
CommentViewer commentViewer) {
ReplyToCommentAction replyAction = new ReplyToCommentActionWithMenu(commentViewer);
replyAction.setImageDescriptor(TasksUiImages.COMMENT_REPLY_SMALL);
toolBarManager.add(replyAction);
}
protected void addActionsToToolbarTitle(ToolBarManager toolBarManager, TaskComment taskComment,
CommentViewer commentViewer) {
}
private void collapseAllComments() {
try {
getTaskEditorPage().setReflow(false);
@SuppressWarnings("unused")
boolean collapsed = false;
List<CommentGroupViewer> viewers = getCommentGroupViewers();
for (int i = 0; i < viewers.size(); i++) {
if (viewers.get(i).isExpanded()) {
viewers.get(i).setFullyExpanded(false);
collapsed = viewers.get(i).isRenderedInSubSection();
// bug 280152: collapse all groups
//break;
}
}
} finally {
getTaskEditorPage().setReflow(true);
}
reflow();
}
private TaskComment convertToTaskComment(TaskDataModel taskDataModel, TaskAttribute commentAttribute) {
TaskComment taskComment = new TaskComment(taskDataModel.getTaskRepository(), taskDataModel.getTask(),
commentAttribute);
taskDataModel.getTaskData().getAttributeMapper().updateTaskComment(taskComment, commentAttribute);
return taskComment;
}
@Override
public void createControl(Composite parent, FormToolkit toolkit) {
initialize();
selectionProvider = new SelectionProviderAdapter();
actionGroup = new CommentActionGroup();
MenuManager menuManager = new MenuManager();
menuManager.setRemoveAllWhenShown(true);
menuManager.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
// get comment and add reply action as first item in the menu
ISelection selection = selectionProvider.getSelection();
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
ReplyToCommentAction replyAction = new ReplyToCommentAction(currentViewer);
manager.add(replyAction);
}
actionGroup.setContext(new ActionContext(selectionProvider.getSelection()));
actionGroup.fillContextMenu(manager);
if (currentViewer != null && currentViewer.getEditor() instanceof RichTextAttributeEditor) {
RichTextAttributeEditor editor = (RichTextAttributeEditor) currentViewer.getEditor();
if (editor.getViewSourceAction().isEnabled()) {
manager.add(new Separator("planning")); //$NON-NLS-1$
manager.add(editor.getViewSourceAction());
}
}
}
});
getTaskEditorPage().getEditorSite().registerContextMenu(ID_POPUP_MENU, menuManager, selectionProvider, false);
commentMenu = menuManager.createContextMenu(parent);
section = createSection(parent, toolkit, hasIncoming);
section.setText(section.getText() + " (" + commentAttributes.size() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
if (commentAttributes.isEmpty()) {
section.setEnabled(false);
} else {
if (hasIncoming) {
expandSection(toolkit, section);
} else {
section.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent event) {
if (section.getClient() == null) {
try {
expandAllInProgress = true;
getTaskEditorPage().setReflow(false);
expandSection(toolkit, section);
} finally {
expandAllInProgress = false;
getTaskEditorPage().setReflow(true);
}
reflow();
}
}
});
}
}
setSection(toolkit, section);
}
@Override
public void dispose() {
super.dispose();
if (actionGroup != null) {
actionGroup.dispose();
}
}
public void expandAllComments(boolean expandViewers) {
try {
expandAllInProgress = true;
suppressExpandViewers = !expandViewers;
getTaskEditorPage().setReflow(false);
if (section != null) {
// the expandAllInProgress flag will ensure that comments in top-level groups have been
// expanded, no need to expand groups explicitly
CommonFormUtil.setExpanded(section, true);
if (expandViewers) {
List<CommentGroupViewer> groupViewers = getCommentGroupViewers();
for (int i = groupViewers.size() - 1; i >= 0; i--) {
if (!groupViewers.get(i).isFullyExpanded()) {
groupViewers.get(i).setFullyExpanded(true);
}
}
}
}
} finally {
expandAllInProgress = false;
suppressExpandViewers = false;
getTaskEditorPage().setReflow(true);
}
reflow();
}
private void expandSection(FormToolkit toolkit, Section section) {
Composite composite = toolkit.createComposite(section);
section.setClient(composite);
composite.setLayout(EditorUtil.createSectionClientLayout());
List<CommentGroupViewer> viewers = getCommentGroupViewers();
for (CommentGroupViewer viewer : viewers) {
Control control = viewer.createControl(composite, toolkit);
if (viewer.isRenderedInSubSection()) {
// align twistie of sub-section with section
GridDataFactory.fillDefaults().grab(true, false).indent(2 * INDENT, 0).applyTo(control);
} else {
GridDataFactory.fillDefaults().grab(true, false).indent(INDENT, 0).applyTo(control);
}
}
}
@Override
protected void fillToolBar(ToolBarManager barManager) {
Action collapseAllAction = new Action("") { //$NON-NLS-1$
@Override
public void run() {
collapseAllComments();
}
};
collapseAllAction.setImageDescriptor(CommonImages.COLLAPSE_ALL_SMALL);
collapseAllAction.setToolTipText(Messages.TaskEditorCommentPart_Collapse_Comments);
barManager.add(collapseAllAction);
Action expandAllAction = new Action("") { //$NON-NLS-1$
@Override
public void run() {
expandAllComments(true);
}
};
expandAllAction.setImageDescriptor(CommonImages.EXPAND_ALL_SMALL);
expandAllAction.setToolTipText(Messages.TaskEditorCommentPart_Expand_Comments);
barManager.add(expandAllAction);
if (commentAttributes.isEmpty()) {
collapseAllAction.setEnabled(false);
expandAllAction.setEnabled(false);
}
}
public CommentGroupStrategy getCommentGroupStrategy() {
return commentGroupStrategy;
}
public void setCommentGroupStrategy(CommentGroupStrategy commentGroupStrategy) {
this.commentGroupStrategy = commentGroupStrategy;
}
public List<CommentGroupViewer> getCommentGroupViewers() {
if (commentGroupViewers != null) {
return commentGroupViewers;
}
// group comments
List<ITaskComment> comments = new ArrayList<ITaskComment>();
for (TaskAttribute commentAttribute : this.commentAttributes) {
comments.add(convertToTaskComment(getModel(), commentAttribute));
}
String currentPersonId = getModel().getTaskRepository().getUserName();
List<CommentGroup> commentGroups = getCommentGroupStrategy().groupComments(comments, currentPersonId);
commentGroupViewers = new ArrayList<CommentGroupViewer>(commentGroups.size());
if (commentGroups.size() > 0) {
for (int i = 0; i < commentGroups.size(); i++) {
CommentGroupViewer viewer = new CommentGroupViewer(commentGroups.get(i));
boolean isLastGroup = i == commentGroups.size() - 1;
viewer.setRenderedInSubSection(!isLastGroup);
commentGroupViewers.add(viewer);
}
}
return commentGroupViewers;
}
private void initialize() {
commentAttributes = getTaskData().getAttributeMapper().getAttributesByType(getTaskData(),
TaskAttribute.TYPE_COMMENT);
if (commentAttributes.size() > 0) {
for (TaskAttribute commentAttribute : commentAttributes) {
if (getModel().hasIncomingChanges(commentAttribute)) {
hasIncoming = true;
break;
}
}
}
}
@Override
public boolean setFormInput(Object input) {
if (input instanceof String) {
String text = (String) input;
if (commentAttributes != null) {
for (TaskAttribute commentAttribute : commentAttributes) {
if (text.equals(commentAttribute.getId())) {
selectReveal(commentAttribute);
}
}
}
}
return super.setFormInput(input);
}
public CommentViewer selectReveal(TaskAttribute commentAttribute) {
if (commentAttribute == null) {
return null;
}
expandAllComments(false);
List<CommentGroupViewer> groupViewers = getCommentGroupViewers();
for (CommentGroupViewer groupViewer : groupViewers) {
for (CommentViewer viewer : groupViewer.getCommentViewers()) {
if (viewer.getTaskAttribute().equals(commentAttribute)) {
// expand section
groupViewer.setExpanded(true);
// EditorUtil is consistent with behavior of outline
EditorUtil.reveal(getTaskEditorPage().getManagedForm().getForm(), commentAttribute.getId());
return viewer;
}
}
}
return null;
}
public boolean isCommentSectionExpanded() {
return section != null && section.isExpanded();
}
public void reflow() {
if (reflow) {
getTaskEditorPage().reflow();
}
}
public void setReflow(boolean reflow) {
this.reflow = reflow;
}
}