1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.atlassian.theplugin.idea.crucible;
17
18 import com.atlassian.theplugin.commons.cfg.CfgManager;
19 import com.atlassian.theplugin.commons.cfg.ServerId;
20 import com.atlassian.theplugin.commons.configuration.PluginConfiguration;
21 import com.atlassian.theplugin.commons.crucible.CrucibleReviewListener;
22 import com.atlassian.theplugin.commons.crucible.ValueNotYetInitialized;
23 import com.atlassian.theplugin.commons.crucible.api.model.*;
24 import com.atlassian.theplugin.commons.crucible.api.model.notification.CrucibleNotification;
25 import com.atlassian.theplugin.commons.remoteapi.ServerData;
26 import com.atlassian.theplugin.commons.util.DateUtil;
27 import com.atlassian.theplugin.configuration.WorkspaceConfigurationBean;
28 import com.atlassian.theplugin.idea.Constants;
29 import com.atlassian.theplugin.idea.MultiTabToolWindow;
30 import com.atlassian.theplugin.idea.ProgressAnimationProvider;
31 import com.atlassian.theplugin.idea.ThePluginProjectComponent;
32 import com.atlassian.theplugin.idea.crucible.editor.ChangeViewer;
33 import com.atlassian.theplugin.idea.crucible.editor.CommentHighlighter;
34 import com.atlassian.theplugin.idea.crucible.tree.AtlassianTreeWithToolbar;
35 import com.atlassian.theplugin.idea.crucible.tree.ReviewItemTreePanel;
36 import com.atlassian.theplugin.idea.ui.BoldLabel;
37 import com.atlassian.theplugin.idea.ui.SwingAppRunner;
38 import com.atlassian.theplugin.util.Htmlizer;
39 import com.intellij.ide.BrowserUtil;
40 import com.intellij.openapi.actionSystem.*;
41 import com.intellij.openapi.progress.ProgressIndicator;
42 import com.intellij.openapi.progress.ProgressManager;
43 import com.intellij.openapi.progress.Task;
44 import com.intellij.openapi.project.Project;
45 import com.intellij.openapi.ui.VerticalFlowLayout;
46 import com.intellij.openapi.util.IconLoader;
47 import com.intellij.util.ui.UIUtil;
48 import org.jetbrains.annotations.NonNls;
49 import org.jetbrains.annotations.NotNull;
50 import org.jetbrains.annotations.Nullable;
51
52 import javax.swing.*;
53 import javax.swing.event.HyperlinkEvent;
54 import javax.swing.event.HyperlinkListener;
55 import java.awt.*;
56 import java.awt.event.ComponentAdapter;
57 import java.awt.event.ComponentEvent;
58 import java.util.Date;
59
60
61
62
63 public class ReviewDetailsToolWindow extends MultiTabToolWindow implements DataProvider {
64 private static final String TOOL_WINDOW_TITLE = "Reviews - Crucible";
65 private ReviewAdapter reviewAdapter;
66 private final CfgManager cfgManager;
67 private final Project project;
68 private final ThePluginProjectComponent pluginProjectComponent;
69 private PluginConfiguration pluginConfiguration;
70 private WorkspaceConfigurationBean workspaceConfiguration;
71
72 private ReviewPanel contentPanel;
73 private ReviewContentParameters contentParams;
74
75
76 protected ReviewDetailsToolWindow(@NotNull CfgManager cfgManager, @NotNull final Project project,
77 @NotNull final ThePluginProjectComponent pluginProjectComponent,
78 @NotNull final PluginConfiguration pluginConfiguration,
79 @NotNull final WorkspaceConfigurationBean workspaceConfiguration) {
80 super(true);
81 this.cfgManager = cfgManager;
82 this.project = project;
83 this.pluginProjectComponent = pluginProjectComponent;
84 this.pluginConfiguration = pluginConfiguration;
85 this.workspaceConfiguration = workspaceConfiguration;
86 }
87
88 @Override
89 protected String getContentKey(ContentParameters params) {
90 ReviewContentParameters cParams = (ReviewContentParameters) params;
91 ReviewAdapter ra = cParams != null ? cParams.reviewAdapter : null;
92 String key = "";
93
94 if (ra != null) {
95 key = ra.getServerData().getServerId() + ra.getPermId().getId();
96 }
97 return key;
98 }
99
100 @Override
101 protected ContentPanel createContentPanel(ContentParameters params) {
102 pluginConfiguration.getGeneralConfigurationData().bumpCounter("r");
103 contentPanel = new ReviewPanel((ReviewContentParameters) params);
104 return contentPanel;
105 }
106
107 public void closeToolWindow(AnActionEvent event) {
108 super.closeToolWindow(TOOL_WINDOW_TITLE, event);
109 CommentHighlighter.removeCommentsInEditors(project);
110 ChangeViewer.removeHighlightersInEditors(project);
111 this.contentParams.reviewAdapter.clearContentCache();
112 }
113
114 public Object getData(@NonNls final String dataId) {
115 if (dataId.equals(Constants.REVIEW)) {
116 return reviewAdapter;
117 }
118 return null;
119 }
120
121
122
123
124
125
126
127
128 public void selectVersionedComment(final ReviewAdapter review, final CrucibleFileInfo file, final Comment comment) {
129 if (contentParams.reviewAdapter.equals(review)) {
130 contentPanel.selectVersionedComment(file, comment);
131 }
132 }
133
134 public void selectGeneralComment(final ReviewAdapter review, final Comment comment) {
135 if (contentParams.reviewAdapter.equals(review)) {
136 contentPanel.selectGeneralComment(comment);
137 }
138 }
139
140 public void selectFile(final ReviewAdapter review, final CrucibleFileInfo file) {
141 if (contentParams.reviewAdapter.equals(review)) {
142 contentPanel.selectFile(file);
143 }
144 }
145
146 private final class ReviewContentParameters implements MultiTabToolWindow.ContentParameters {
147 private final ReviewAdapter reviewAdapter;
148 private boolean refreshDetails;
149
150 private ReviewContentParameters(ReviewAdapter reviewAdapter, final boolean refreshDetails) {
151 this.reviewAdapter = reviewAdapter;
152 this.refreshDetails = refreshDetails;
153 }
154 }
155
156 public void showReview(ReviewAdapter adapter, boolean refreshDetails) {
157 this.reviewAdapter = adapter;
158 if (workspaceConfiguration.getCrucibleConfiguration() != null) {
159 workspaceConfiguration.getCrucibleConfiguration()
160 .getCrucibleFilters().getRecenltyOpenFilter().addRecentlyOpenReview(adapter);
161 }
162 contentParams = new ReviewContentParameters(adapter, refreshDetails);
163 showToolWindow(project, contentParams, TOOL_WINDOW_TITLE,
164 Constants.CRUCIBLE_REVIEW_PANEL_ICON, Constants.CRUCIBLE_REVIEW_TAB_ICON);
165 }
166
167 public AtlassianTreeWithToolbar getAtlassianTreeWithToolbar() {
168 if (contentParams != null && getContentPanel(getContentKey(contentParams)) != null) {
169 return ((ReviewPanel) getContentPanel(getContentKey(contentParams)))
170 .commentsPanel.getReviewItemTreePanel().getAtlassianTreeWithToolbar();
171 }
172 return null;
173 }
174
175 public void switchFilter() {
176 if (contentParams != null && getContentPanel(getContentKey(contentParams)) != null) {
177 ((ReviewPanel) getContentPanel(getContentKey(contentParams))).commentsPanel.getReviewItemTreePanel().switchFilter();
178 }
179 }
180
181 private final class ReviewPanel extends MultiTabToolWindow.ContentPanel implements CrucibleReviewListener {
182 private final ReviewContentParameters params;
183 private DetailsPanel detailsPanel;
184 private SummaryPanel summaryPanel;
185 private CommentsPanel commentsPanel;
186 private static final String TAB_DETAILS = "Details";
187 private static final String TAB_FILES_AND_COMMENTS = "Files and Comments";
188 private JTabbedPane tabs;
189
190 private ReviewPanel(ReviewContentParameters params) {
191 this.params = params;
192
193 tabs = new JTabbedPane();
194 detailsPanel = new DetailsPanel(params.reviewAdapter);
195
196 tabs.addTab(TAB_DETAILS, detailsPanel);
197 commentsPanel = new CommentsPanel(params.refreshDetails);
198 tabs.addTab(TAB_FILES_AND_COMMENTS, commentsPanel);
199
200 setLayout(new GridBagLayout());
201 GridBagConstraints gbc = new GridBagConstraints();
202 gbc.fill = GridBagConstraints.BOTH;
203 gbc.gridx = 0;
204 gbc.gridy = 0;
205 gbc.weightx = 1.0;
206 gbc.weighty = 0.0;
207 gbc.insets = new Insets(Constants.DIALOG_MARGIN / 2, Constants.DIALOG_MARGIN, 0, 0);
208 summaryPanel = new SummaryPanel();
209 add(summaryPanel, gbc);
210 gbc.gridy++;
211 gbc.weighty = 1.0;
212 gbc.insets = new Insets(0, 0, 0, 0);
213 add(tabs, gbc);
214
215 if (params.reviewAdapter != null) {
216 params.reviewAdapter.addReviewListener(this);
217 }
218 refresh();
219 }
220
221 public void refresh() {
222
223 }
224
225 @Override
226 public String getTitle() {
227 return params.reviewAdapter.getPermId().getId();
228 }
229
230 @Override
231 public void unregister() {
232 if (params != null) {
233 params.reviewAdapter.removeReviewListener(this);
234 }
235
236 commentsPanel.unregisterListeners();
237 }
238
239 public String getKey() {
240 if (params != null && params.reviewAdapter != null) {
241 ReviewAdapter ra = params.reviewAdapter;
242 return ra.getPermId().getId();
243 }
244 return "";
245 }
246
247 public ContentParameters getContentParameters() {
248 return params;
249 }
250
251 public CommentsPanel getCommentsPanel() {
252 return commentsPanel;
253 }
254
255 public void createdOrEditedVersionedCommentReply(final ReviewAdapter review, final PermId file,
256 final VersionedComment parentComment,
257 final
258 VersionedComment comment) {
259 }
260
261 public void createdOrEditedGeneralCommentReply(final ReviewAdapter review, final GeneralComment parentComment,
262 final GeneralComment comment) {
263 }
264
265 public void createdOrEditedGeneralComment(final ReviewAdapter review, final GeneralComment comment) {
266 }
267
268 public void createdOrEditedVersionedComment(final ReviewAdapter review, final PermId file,
269 final VersionedComment comment) {
270 }
271
272 public void removedComment(final ReviewAdapter review, final Comment comment) {
273 }
274
275 public void publishedGeneralComment(final ReviewAdapter review, final GeneralComment comment) {
276 }
277
278 public void publishedVersionedComment(final ReviewAdapter review, final PermId filePermId,
279 final VersionedComment comment) {
280 }
281
282 public void reviewChanged(final ReviewAdapter review, final java.util.List<CrucibleNotification> notifications) {
283 summaryPanel.refresh();
284 detailsPanel.refresh();
285 }
286
287 public void selectVersionedComment(final CrucibleFileInfo file, final Comment comment) {
288
289 tabs.setSelectedComponent(commentsPanel);
290
291
292 commentsPanel.selectVersionedComment(file, comment);
293 }
294
295 public void selectGeneralComment(final Comment comment) {
296
297 tabs.setSelectedComponent(commentsPanel);
298
299
300 commentsPanel.selectGeneralComment(comment);
301 }
302
303 public void selectFile(final CrucibleFileInfo file) {
304
305 tabs.setSelectedComponent(commentsPanel);
306
307
308 commentsPanel.selectFile(file);
309 }
310
311 private final class CommentsPanel extends JPanel {
312 private ReviewItemTreePanel reviewItemTreePanel;
313 private ProgressAnimationProvider progressAnimation = new ProgressAnimationProvider();
314
315 private CommentsPanel(final boolean retrieveDetails) {
316 super(new BorderLayout());
317 setBackground(UIUtil.getTreeTextBackground());
318 reviewItemTreePanel = new ReviewItemTreePanel(cfgManager, project,
319 CrucibleFilteredModelProvider.Filter.FILES_ALL,
320 pluginProjectComponent);
321 reviewItemTreePanel.getProgressAnimation().configure(reviewItemTreePanel,
322 reviewItemTreePanel, BorderLayout.CENTER);
323 add(reviewItemTreePanel, BorderLayout.CENTER);
324
325 registerListeners();
326 progressAnimation.configure(this, reviewItemTreePanel, BorderLayout.CENTER);
327 progressAnimation.startProgressAnimation();
328
329 Task.Backgroundable task = new Task.Backgroundable(project, "Retrieving Crucible Data", false) {
330 @Override
331 public void run(@NotNull final ProgressIndicator indicator) {
332 reviewItemTreePanel.showReview(params.reviewAdapter, retrieveDetails);
333 }
334
335 @Override
336 public void onCancel() {
337 progressAnimation.stopProgressAnimation();
338 }
339
340 @Override
341 public void onSuccess() {
342 progressAnimation.stopProgressAnimation();
343 }
344 };
345
346 ProgressManager.getInstance().run(task);
347 }
348
349 private void registerListeners() {
350 reviewItemTreePanel.startListeningForCredentialChanges(project, params.reviewAdapter);
351 params.reviewAdapter.addReviewListener(reviewItemTreePanel.getReviewListener());
352 }
353
354 public void unregisterListeners() {
355 reviewItemTreePanel.stopListeningForCredentialChanges();
356 params.reviewAdapter.removeReviewListener(reviewItemTreePanel.getReviewListener());
357 }
358
359 public ReviewItemTreePanel getReviewItemTreePanel() {
360 return reviewItemTreePanel;
361 }
362
363 public void selectVersionedComment(final CrucibleFileInfo file, final Comment comment) {
364 reviewItemTreePanel.selectVersionedComment(file, comment);
365 }
366
367 public void selectGeneralComment(final Comment comment) {
368 reviewItemTreePanel.selectGeneralComment(comment);
369 }
370
371 public void selectFile(final CrucibleFileInfo file) {
372 reviewItemTreePanel.selectFile(file);
373 }
374 }
375
376 private class SummaryPanel extends JPanel implements DataProvider {
377
378 private JEditorPane summary;
379
380 public SummaryPanel() {
381 setLayout(new GridBagLayout());
382 GridBagConstraints gbc = new GridBagConstraints();
383
384 gbc.gridy = 0;
385 gbc.gridx = 0;
386 gbc.anchor = GridBagConstraints.LINE_START;
387 gbc.fill = GridBagConstraints.HORIZONTAL;
388 gbc.weightx = 1.0;
389 summary = new JEditorPane();
390 summary.setContentType("text/html");
391 summary.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);
392 refresh();
393 summary.setEditable(false);
394 summary.addHyperlinkListener(new HyperlinkListener() {
395 public void hyperlinkUpdate(HyperlinkEvent e) {
396 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
397 BrowserUtil.launchBrowser(e.getURL().toString());
398 }
399 }
400 });
401
402 summary.setFont(summary.getFont().deriveFont(Font.BOLD));
403 summary.setOpaque(false);
404 JPanel p = new JPanel();
405 p.setLayout(new GridBagLayout());
406 GridBagConstraints gbcp = new GridBagConstraints();
407 gbcp.fill = GridBagConstraints.BOTH;
408 gbcp.weightx = 1.0;
409 gbcp.weighty = 1.0;
410 gbcp.gridx = 0;
411 gbcp.gridy = 0;
412 p.add(summary, gbcp);
413 add(p, gbc);
414
415 gbc.gridy++;
416
417 ActionManager manager = ActionManager.getInstance();
418 if (manager != null) {
419 ActionGroup group = (ActionGroup) manager.getAction("ThePlugin.Reviews.SingleReview.ToolBar");
420 ActionToolbar toolbar = manager.createActionToolbar(getContentKey(params), group, true);
421 toolbar.setTargetComponent(this);
422 JComponent comp = toolbar.getComponent();
423 add(comp, gbc);
424 }
425 }
426
427 public void refresh() {
428 String txt = "<html><body><a href=\"" + params.reviewAdapter.getReviewUrl() + "\">"
429 + params.reviewAdapter.getPermId().getId() + "</a> "
430 + params.reviewAdapter.getName() + "</body></html>";
431 summary.setText(txt);
432 }
433
434 @Nullable
435 public Object getData(@NonNls String dataId) {
436 if (dataId.equals(Constants.REVIEW_TOOL_WINDOW)) {
437 return this;
438 } else if (dataId.equals(Constants.REVIEW_WINDOW_ENABLED)) {
439 return true;
440 } else if (dataId.equals(Constants.REVIEW) && contentPanel != null && params != null) {
441 return params.reviewAdapter;
442 }
443 return null;
444 }
445 }
446
447 }
448
449 public ReviewAdapter getReview() {
450 return reviewAdapter;
451 }
452 }
453
454
455
456
457 class DetailsPanel extends JPanel {
458 private JScrollPane scroll;
459
460 private final ReviewAdapter ra;
461 private static final int MAX_DISPLAYED_LINK_LENGTH = 80;
462
463 public DetailsPanel(final ReviewAdapter reviewAdapter) {
464 this.ra = reviewAdapter;
465 setLayout(new GridBagLayout());
466
467 GridBagConstraints gbc = new GridBagConstraints();
468 gbc.gridx = 0;
469 gbc.gridy = 0;
470 gbc.weightx = 1.0;
471 gbc.weighty = 1.0;
472 gbc.fill = GridBagConstraints.BOTH;
473
474 scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
475 final JPanel panel = createBody();
476 scroll.setViewportView(panel);
477 scroll.setBorder(BorderFactory.createEmptyBorder());
478 add(scroll, gbc);
479 }
480
481 private JPanel createBody() {
482 final JPanel body = new JPanel();
483
484 body.setLayout(new GridBagLayout());
485 body.setOpaque(true);
486 body.setBackground(Color.WHITE);
487
488 GridBagConstraints gbc1 = new GridBagConstraints();
489 GridBagConstraints gbc2 = new GridBagConstraints();
490 gbc1.anchor = GridBagConstraints.FIRST_LINE_START;
491 gbc2.anchor = GridBagConstraints.FIRST_LINE_START;
492 gbc1.insets = new Insets(Constants.DIALOG_MARGIN / 2, Constants.DIALOG_MARGIN,
493 Constants.DIALOG_MARGIN / 2, Constants.DIALOG_MARGIN);
494 gbc2.insets = new Insets(Constants.DIALOG_MARGIN / 2, Constants.DIALOG_MARGIN,
495 Constants.DIALOG_MARGIN / 2, Constants.DIALOG_MARGIN);
496 gbc2.fill = GridBagConstraints.HORIZONTAL;
497 gbc2.weightx = 1.0;
498 gbc1.gridx = 0;
499 gbc2.gridx = gbc1.gridx + 1;
500 gbc1.gridy = 0;
501 gbc2.gridy = 0;
502
503 body.add(new BoldLabel("Statement of Objectives"), gbc1);
504
505 final JEditorPane statementOfObjectives = new JEditorPane() {
506
507 };
508 statementOfObjectives.setEditable(false);
509 statementOfObjectives.setOpaque(true);
510 statementOfObjectives.setBackground(Color.WHITE);
511 statementOfObjectives.setContentType("text/html");
512 statementOfObjectives.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);
513 Htmlizer htmlizer = new Htmlizer(MAX_DISPLAYED_LINK_LENGTH);
514 String sooText = htmlizer.htmlizeHyperlinks(ra.getDescription());
515 sooText = htmlizer.replaceWhitespace(sooText);
516 statementOfObjectives.setText("<html><body>" + sooText + "</body></html>");
517 statementOfObjectives.addHyperlinkListener(new HyperlinkListener() {
518 public void hyperlinkUpdate(HyperlinkEvent e) {
519 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
520 BrowserUtil.launchBrowser(e.getURL().toString());
521 }
522 }
523 });
524
525 statementOfObjectives.setBorder(null);
526 body.add(statementOfObjectives, gbc2);
527 scroll.addComponentListener(new ComponentAdapter() {
528 @Override
529 public void componentResized(ComponentEvent e) {
530
531
532
533
534
535
536
537
538
539
540
541
542
543 body.setPreferredSize(null);
544
545 body.setPreferredSize(new Dimension(scroll.getViewport().getWidth(),
546 body.getPreferredSize().height));
547
548 body.validate();
549 }
550 });
551
552 gbc1.gridy++;
553 gbc2.gridy++;
554 gbc1.insets = new Insets(0, Constants.DIALOG_MARGIN,
555 Constants.DIALOG_MARGIN / 2, Constants.DIALOG_MARGIN);
556 gbc2.insets = new Insets(0, Constants.DIALOG_MARGIN,
557 Constants.DIALOG_MARGIN / 2, Constants.DIALOG_MARGIN);
558 body.add(new BoldLabel("State"), gbc1);
559 body.add(new JLabel(ra.getState().getDisplayName()), gbc2);
560 gbc1.gridy++;
561 gbc2.gridy++;
562 body.add(new BoldLabel("Open"), gbc1);
563
564 body.add(new JLabel(DateUtil.getRelativeBuildTime(ra.getCreateDate())), gbc2);
565
566 gbc1.gridy++;
567 gbc2.gridy++;
568 body.add(new BoldLabel("Author"), gbc1);
569 body.add(new JLabel(ra.getCreator().getDisplayName()), gbc2);
570
571 gbc1.gridy++;
572 gbc2.gridy++;
573 body.add(new BoldLabel("Moderator"), gbc1);
574 body.add(new JLabel(ra.getModerator().getDisplayName()), gbc2);
575
576 gbc1.gridy++;
577 gbc2.gridy++;
578 body.add(new BoldLabel("Reviewers"), gbc1);
579
580 JPanel reviewers = new JPanel();
581 VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false);
582 layout.setHgap(0);
583 layout.setVgap(0);
584 Container container = new Container();
585 layout.layoutContainer(container);
586
587 reviewers.setLayout(layout);
588
589 Icon reviewCompletedIcon = IconLoader.getIcon("/icons/icn_complete.gif");
590 try {
591 for (Reviewer reviewer : ra.getReviewers()) {
592 JLabel label = new JLabel(reviewer.getDisplayName(),
593 reviewer.isCompleted() ? reviewCompletedIcon : null,
594 SwingConstants.LEFT);
595 label.setOpaque(true);
596 label.setBackground(Color.WHITE);
597 label.setHorizontalTextPosition(SwingUtilities.LEFT);
598 label.setHorizontalAlignment(SwingUtilities.LEFT);
599 reviewers.add(label);
600 }
601
602 body.add(reviewers, gbc2);
603 } catch (ValueNotYetInitialized valueNotYetInitialized) {
604
605 }
606
607 gbc1.gridy++;
608 gbc1.weighty = 1.0;
609 gbc1.fill = GridBagConstraints.VERTICAL;
610 JPanel filler = new JPanel();
611 filler.setOpaque(true);
612 filler.setBackground(Color.WHITE);
613 body.add(filler, gbc1);
614
615 return body;
616 }
617
618 public static void main(String[] args) {
619 ServerData cruc = new ServerData("my crucible server", (new ServerId()).toString(), "", "", "");
620 ReviewBean review = new ReviewBean("myreviewbean");
621 ReviewAdapter reviewAdapter = new ReviewAdapter(review, cruc);
622 review.setDescription("My description dfjlslj ldfsjalkfsdjlkj sld"
623 + "jldfjal jfdlkjafl jldfsjalfj ldsj fldjsf; ljWojciech Seliga fjdsalkfjs df\nA new line above\nand then some"
624 + "very very very long lllllllllllllloooong string.");
625 review.setName("My review name");
626 review.setState(State.REVIEW);
627 review.setCreateDate(new Date());
628 final ReviewerBean author = new ReviewerBean();
629 author.setUserName("wseliga");
630 author.setDisplayName("Wojciech Seliga");
631 review.setAuthor(author);
632 review.setCreator(author);
633 review.setModerator(author);
634
635 SwingAppRunner.run(new DetailsPanel(reviewAdapter));
636 }
637
638 public void createdOrEditedVersionedCommentReply(final ReviewAdapter review, final PermId file,
639 final VersionedComment parentComment,
640 final
641 VersionedComment comment) {
642 }
643
644 public void createdOrEditedGeneralCommentReply(final ReviewAdapter review, final GeneralComment parentComment,
645 final GeneralComment comment) {
646 }
647
648 public void createdOrEditedGeneralComment(final ReviewAdapter review, final GeneralComment comment) {
649 }
650
651 public void createdOrEditedVersionedComment(final ReviewAdapter review, final PermId file, final VersionedComment comment) {
652 }
653
654 public void removedComment(final ReviewAdapter review, final Comment comment) {
655 }
656
657 public void publishedGeneralComment(final ReviewAdapter review, final GeneralComment comment) {
658 }
659
660 public void publishedVersionedComment(final ReviewAdapter review, final PermId filePermId, final VersionedComment comment) {
661 }
662
663 public void refresh() {
664 final JPanel panel = createBody();
665
666 scroll.setViewportView(panel);
667 scroll.validate();
668 validate();
669 }
670 }