PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/com.atlassian.connector.eclipse.crucible.ui/src/com/atlassian/connector/eclipse/internal/crucible/ui/editor/parts/AbstractCommentPart.java

https://github.com/spingel/mylyn-reviews
Java | 340 lines | 248 code | 68 blank | 24 comment | 46 complexity | dbd71daf23324c81d861968cca04e1c4 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2009 Atlassian and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * Atlassian - initial API and implementation
  10. ******************************************************************************/
  11. package com.atlassian.connector.eclipse.internal.crucible.ui.editor.parts;
  12. import com.atlassian.connector.eclipse.internal.crucible.core.CrucibleConstants;
  13. import com.atlassian.connector.eclipse.internal.crucible.core.CrucibleUtil;
  14. import com.atlassian.connector.eclipse.internal.crucible.ui.CrucibleImages;
  15. import com.atlassian.connector.eclipse.internal.crucible.ui.CrucibleUiPlugin;
  16. import com.atlassian.connector.eclipse.internal.crucible.ui.CrucibleUiUtil;
  17. import com.atlassian.connector.eclipse.internal.crucible.ui.IReviewAction;
  18. import com.atlassian.connector.eclipse.internal.crucible.ui.IReviewActionListener;
  19. import com.atlassian.connector.eclipse.internal.crucible.ui.AvatarImages.AvatarSize;
  20. import com.atlassian.connector.eclipse.internal.crucible.ui.actions.EditCommentAction;
  21. import com.atlassian.connector.eclipse.internal.crucible.ui.actions.PostDraftCommentAction;
  22. import com.atlassian.connector.eclipse.internal.crucible.ui.actions.RemoveCommentAction;
  23. import com.atlassian.connector.eclipse.internal.crucible.ui.actions.ReplyToCommentAction;
  24. import com.atlassian.connector.eclipse.ui.commons.AtlassianUiUtil;
  25. import com.atlassian.connector.eclipse.ui.forms.SizeCachingComposite;
  26. import com.atlassian.theplugin.commons.crucible.api.model.Comment;
  27. import com.atlassian.theplugin.commons.crucible.api.model.CustomField;
  28. import com.atlassian.theplugin.commons.crucible.api.model.Review;
  29. import org.eclipse.jface.action.Action;
  30. import org.eclipse.jface.dialogs.MessageDialog;
  31. import org.eclipse.jface.layout.GridDataFactory;
  32. import org.eclipse.jface.layout.GridLayoutFactory;
  33. import org.eclipse.jface.resource.ImageDescriptor;
  34. import org.eclipse.jface.viewers.StructuredSelection;
  35. import org.eclipse.mylyn.internal.tasks.ui.editors.RichTextEditor;
  36. import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorExtensions;
  37. import org.eclipse.mylyn.tasks.core.ITask;
  38. import org.eclipse.mylyn.tasks.core.TaskRepository;
  39. import org.eclipse.mylyn.tasks.ui.TasksUi;
  40. import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorExtension;
  41. import org.eclipse.swt.SWT;
  42. import org.eclipse.swt.events.FocusEvent;
  43. import org.eclipse.swt.events.FocusListener;
  44. import org.eclipse.swt.layout.GridLayout;
  45. import org.eclipse.swt.widgets.Composite;
  46. import org.eclipse.swt.widgets.Control;
  47. import org.eclipse.swt.widgets.Label;
  48. import org.eclipse.ui.forms.widgets.FormToolkit;
  49. import org.eclipse.ui.forms.widgets.Section;
  50. import java.text.DateFormat;
  51. import java.util.ArrayList;
  52. import java.util.Comparator;
  53. import java.util.List;
  54. import java.util.Map;
  55. /**
  56. * A UI part to represent a comment in a review
  57. *
  58. * @author Shawn Minto
  59. * @author Thomas Ehrnhoefer
  60. */
  61. @SuppressWarnings("restriction")
  62. public abstract class AbstractCommentPart<V extends ExpandablePart<Comment, V>> extends ExpandablePart<Comment, V> {
  63. protected Comment comment;
  64. // protected final CrucibleFile crucibleFile;
  65. protected Control commentTextComposite;
  66. protected SizeCachingComposite sectionClient;
  67. public AbstractCommentPart(Comment comment, Review crucibleReview) {
  68. super(crucibleReview);
  69. this.comment = comment;
  70. // this.crucibleFile = crucibleFile;
  71. }
  72. @Override
  73. protected String getSectionHeaderText() {
  74. String headerText = comment.getAuthor().getDisplayName() + " ";
  75. headerText += DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(
  76. comment.getCreateDate());
  77. return headerText;
  78. }
  79. @Override
  80. protected Comparator<Comment> getComparator() {
  81. return new Comparator<Comment>() {
  82. public int compare(Comment o1, Comment o2) {
  83. if (o1 != null && o2 != null) {
  84. return o1.getCreateDate().compareTo(o2.getCreateDate());
  85. }
  86. return 0;
  87. }
  88. };
  89. }
  90. // TODO handle changed highlighting properly
  91. protected final Control createOrUpdateControl(Composite parentComposite, FormToolkit toolkit) {
  92. Control createdControl = null;
  93. if (getSection() == null) {
  94. Control newControl = createControl(parentComposite, toolkit);
  95. setIncomming(true);
  96. createdControl = newControl;
  97. } else {
  98. if (commentTextComposite != null && !commentTextComposite.isDisposed()) {
  99. Composite parent = commentTextComposite.getParent();
  100. commentTextComposite.dispose();
  101. createCommentArea(toolkit, sectionClient);
  102. if (parent.getChildren().length > 0) {
  103. commentTextComposite.moveAbove(parent.getChildren()[0]);
  104. }
  105. }
  106. updateChildren(sectionClient, toolkit, true, comment.getReplies());
  107. createdControl = getSection();
  108. }
  109. if (sectionClient != null && !sectionClient.isDisposed()) {
  110. sectionClient.clearCache();
  111. }
  112. getSection().layout(true, true);
  113. update();
  114. return createdControl;
  115. }
  116. @Override
  117. protected Composite createSectionContents(Section section, FormToolkit toolkit) {
  118. // CHECKSTYLE:MAGIC:OFF
  119. section.clientVerticalSpacing = 0;
  120. sectionClient = new SizeCachingComposite(section, SWT.NONE);
  121. toolkit.adapt(sectionClient);
  122. GridLayout layout = new GridLayout(1, false);
  123. layout.marginTop = 0;
  124. layout.marginLeft = 9;
  125. sectionClient.setLayout(layout);
  126. GridDataFactory.fillDefaults().grab(true, false).applyTo(sectionClient);
  127. createCommentArea(toolkit, sectionClient);
  128. updateChildren(sectionClient, toolkit, false, comment.getReplies());
  129. // CHECKSTYLE:MAGIC:ON
  130. return sectionClient;
  131. }
  132. protected void createCommentArea(FormToolkit toolkit, Composite parentComposite) {
  133. final Composite twoColumnComposite = new Composite(parentComposite, SWT.NONE);
  134. twoColumnComposite.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).create());
  135. GridDataFactory.fillDefaults().hint(500, SWT.DEFAULT).applyTo(twoColumnComposite);
  136. toolkit.adapt(twoColumnComposite);
  137. final Label avatarLabel = new Label(twoColumnComposite, SWT.NONE);
  138. toolkit.adapt(avatarLabel, false, false);
  139. avatarLabel.setImage(CrucibleUiPlugin.getDefault().getAvatarsCache().getAvatarOrDefaultImage(
  140. comment.getAuthor(), AvatarSize.LARGE));
  141. GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.TOP).applyTo(avatarLabel);
  142. commentTextComposite = createReadOnlyText(toolkit, twoColumnComposite, getCommentText());
  143. GridDataFactory.fillDefaults().grab(true, true).applyTo(commentTextComposite);
  144. }
  145. // TODO could be moved to a util method
  146. private String getCommentText() {
  147. String commentText = comment.getMessage();
  148. String customFieldsString = "";
  149. if (comment.getCustomFields() != null && comment.getCustomFields().size() > 0) {
  150. Map<String, CustomField> customFields = comment.getCustomFields();
  151. CustomField classificationField = customFields.get(CrucibleConstants.CLASSIFICATION_CUSTOM_FIELD_KEY);
  152. CustomField rankField = customFields.get(CrucibleConstants.RANK_CUSTOM_FIELD_KEY);
  153. String classification = null;
  154. if (classificationField != null) {
  155. classification = classificationField.getValue();
  156. }
  157. String rank = null;
  158. if (rankField != null) {
  159. rank = rankField.getValue();
  160. }
  161. if (rank != null || classification != null) {
  162. customFieldsString = "(";
  163. if (comment.isDefectApproved() || comment.isDefectRaised()) {
  164. customFieldsString += "Defect, ";
  165. }
  166. }
  167. if (classification != null) {
  168. customFieldsString += "Classification:" + classification;
  169. if (rank != null) {
  170. customFieldsString += ", ";
  171. }
  172. }
  173. if (rank != null) {
  174. customFieldsString += "Rank:" + rank;
  175. }
  176. if (customFieldsString.length() > 0) {
  177. customFieldsString += ")";
  178. }
  179. }
  180. if (customFieldsString.length() > 0) {
  181. commentText += " " + customFieldsString;
  182. }
  183. return commentText;
  184. }
  185. @Override
  186. protected String getAnnotationText() {
  187. String text = "";
  188. if (comment.isDraft()) {
  189. text = "DRAFT ";
  190. }
  191. return text;
  192. }
  193. private Control createReadOnlyText(FormToolkit toolkit, Composite composite, String value) {
  194. int style = SWT.FLAT | SWT.READ_ONLY | SWT.MULTI | SWT.WRAP;
  195. ITask task = CrucibleUiUtil.getCrucibleTask(crucibleReview);
  196. TaskRepository repository = TasksUi.getRepositoryManager().getRepository(task.getConnectorKind(),
  197. task.getRepositoryUrl());
  198. TaskEditorExtensions.setTaskEditorExtensionId(repository, AtlassianUiUtil.CONFLUENCE_WIKI_TASK_EDITOR_EXTENSION);
  199. AbstractTaskEditorExtension extension = TaskEditorExtensions.getTaskEditorExtension(repository);
  200. final RichTextEditor editor = new RichTextEditor(repository, style, null, extension);
  201. editor.setReadOnly(true);
  202. editor.setText(value);
  203. editor.createControl(composite, toolkit);
  204. // HACK: this is to make sure that we can't have multiple things highlighted
  205. editor.getViewer().getTextWidget().addFocusListener(new FocusListener() {
  206. public void focusGained(FocusEvent e) {
  207. }
  208. public void focusLost(FocusEvent e) {
  209. editor.getViewer().getTextWidget().setSelection(0);
  210. }
  211. });
  212. return editor.getControl();
  213. }
  214. @Override
  215. protected boolean canExpand() {
  216. return !comment.isReply();
  217. }
  218. @Override
  219. protected boolean hasContents() {
  220. return true;
  221. }
  222. @Override
  223. protected ImageDescriptor getAnnotationImage() {
  224. if (comment.isDefectRaised() || comment.isDefectApproved()) {
  225. // TODO get an image for a bug
  226. return null;
  227. }
  228. return null;
  229. }
  230. @Override
  231. protected List<IReviewAction> getToolbarActions(boolean isExpanded) {
  232. List<IReviewAction> actions = new ArrayList<IReviewAction>();
  233. if (isExpanded) {
  234. if (!comment.isReply() && CrucibleUtil.canAddCommentToReview(crucibleReview)) {
  235. ReplyToCommentAction action = new ReplyToCommentAction();
  236. action.selectionChanged(new StructuredSelection(comment));
  237. actions.add(action);
  238. }
  239. if (CrucibleUiUtil.canModifyComment(crucibleReview, comment)) {
  240. EditCommentAction action = new EditCommentAction();
  241. action.selectionChanged(new StructuredSelection(comment));
  242. actions.add(action);
  243. if (!comment.isReply() && comment.getReplies().size() > 0) {
  244. actions.add(new CannotRemoveCommentAction("Remove Comment", CrucibleImages.COMMENT_DELETE));
  245. } else {
  246. RemoveCommentAction action1 = new RemoveCommentAction();
  247. action1.selectionChanged(new StructuredSelection(comment));
  248. actions.add(action1);
  249. }
  250. if (CrucibleUtil.canPublishDraft(comment)) {
  251. PostDraftCommentAction action1 = new PostDraftCommentAction();
  252. action1.selectionChanged(new StructuredSelection(comment));
  253. actions.add(action1);
  254. }
  255. }
  256. }
  257. return actions;
  258. }
  259. private final class CannotRemoveCommentAction extends Action implements IReviewAction {
  260. public CannotRemoveCommentAction(String text, ImageDescriptor icon) {
  261. super(text);
  262. setImageDescriptor(icon);
  263. }
  264. public void setActionListener(IReviewActionListener listner) {
  265. }
  266. @Override
  267. public void run() {
  268. MessageDialog.openInformation(getSection().getShell(), "Delete",
  269. "Cannot delete comment with replies. You must delete replies first.");
  270. }
  271. }
  272. }