View Javadoc

1   package org.kuali.student.common.ui.client.widgets.commenttool;
2   
3   import java.text.DateFormat;
4   import java.text.SimpleDateFormat;
5   import java.util.ArrayList;
6   import java.util.Collections;
7   import java.util.Comparator;
8   import java.util.Date;
9   import java.util.List;
10  import java.util.Map;
11  
12  import org.kuali.student.common.ui.client.application.Application;
13  import org.kuali.student.common.ui.client.application.KSAsyncCallback;
14  import org.kuali.student.common.ui.client.configurable.mvc.HasReferenceId;
15  import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
16  import org.kuali.student.common.ui.client.mvc.Callback;
17  import org.kuali.student.common.ui.client.mvc.Controller;
18  import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
19  import org.kuali.student.common.ui.client.mvc.dto.ReferenceModel;
20  import org.kuali.student.common.ui.client.service.CommentRpcService;
21  import org.kuali.student.common.ui.client.service.CommentRpcServiceAsync;
22  import org.kuali.student.common.ui.client.widgets.KSButton;
23  import org.kuali.student.common.ui.client.widgets.KSLabel;
24  import org.kuali.student.common.ui.client.widgets.KSLightBox;
25  import org.kuali.student.common.ui.client.widgets.KSTextArea;
26  import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
27  import org.kuali.student.common.ui.client.widgets.buttongroups.OkGroup;
28  import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations.OkEnum;
29  import org.kuali.student.common.ui.client.widgets.dialog.ConfirmationDialog;
30  import org.kuali.student.common.ui.client.widgets.layout.VerticalFlowPanel;
31  import org.kuali.student.core.comment.dto.CommentInfo;
32  import org.kuali.student.core.dto.RichTextInfo;
33  import org.kuali.student.core.dto.StatusInfo;
34  import org.kuali.student.core.dto.DtoConstants.DtoState;
35  
36  import com.google.gwt.core.client.GWT;
37  import com.google.gwt.dom.client.Style;
38  import com.google.gwt.event.dom.client.ClickEvent;
39  import com.google.gwt.event.dom.client.ClickHandler;
40  import com.google.gwt.event.dom.client.KeyUpEvent;
41  import com.google.gwt.event.dom.client.KeyUpHandler;
42  import com.google.gwt.user.client.Window;
43  import com.google.gwt.user.client.rpc.AsyncCallback;
44  import com.google.gwt.user.client.ui.FlexTable;
45  import com.google.gwt.user.client.ui.FlowPanel;
46  import com.google.gwt.user.client.ui.HTML;
47  import com.google.gwt.user.client.ui.HorizontalPanel;
48  import com.google.gwt.user.client.ui.Widget;
49  
50  public class CommentTool implements HasReferenceId {
51  
52      private CommentRpcServiceAsync commentServiceAsync = GWT.create(CommentRpcService.class);
53      private String referenceId;
54      private String referenceTypeKey;
55      private String referenceType;
56      private String referenceState;
57      private KSLightBox commentLightBox;
58      private HTML loggedInUserNameHTML = new HTML();
59      private String loggedInUserId;
60      private KSTextArea commentTextArea = new KSTextArea();
61      private KSButton cancelEditButton = new KSButton("Cancel");
62      private KSButton submitCommentButton = new KSButton("Submit");
63      private FlexTable commentsTableLayout = new FlexTable();
64      private static final DateFormat df = new SimpleDateFormat("MMMM dd, yyyy - hh:mmaaa");
65      private Controller controller;    
66      private Enum<?> viewEnum;
67      private String viewName;    //View name is being used as menu item label   
68      VerticalFlowPanel loggedInLabelsPanel = new VerticalFlowPanel();
69      VerticalFlowPanel commentEditPanel = new VerticalFlowPanel();
70      KSLabel notAuthorizedToAddComments = new KSLabel("The document must be saved before Comments can be added.");
71      private EditMode editMode = EditMode.ADD_COMMENT;
72      private CommentInfo selectedComment;
73      private List<Callback<EditMode>> editControlsCallbacks = new ArrayList<Callback<EditMode>>();
74      private String commentTypeKey;
75      private Map<String, String> referenceAttributes;
76      private KSLabel proposalTitle = new KSLabel();
77      private String title;
78  
79      private enum EditMode {
80          ADD_COMMENT, UPDATE_COMMENT
81      }
82      
83      public CommentTool(Enum<?> viewEnum, String viewName, String commentTypeKey, String title) {
84          this.viewName = viewName;
85          this.viewEnum = viewEnum;
86          this.commentTypeKey = commentTypeKey;
87          this.title = title;
88          init();
89          
90      }
91      
92      public Controller getController() {
93          return this.controller;
94      }
95  
96  
97      public void setController(Controller controller){
98          this.controller = controller;
99      }
100 
101     
102     public Widget asWidget(){
103         return commentLightBox.getWidget();
104     }
105     
106     private OkGroup buttonPanel = new OkGroup(new Callback<OkEnum>(){
107 
108         @Override
109         public void exec(OkEnum result) {
110             if(result == OkEnum.Ok){
111             }
112 
113         }
114     });
115     
116     private void init() {
117         commentLightBox = new KSLightBox("Comments");
118         VerticalFlowPanel contentPanel = new VerticalFlowPanel();
119         // light box title and instructions
120         SectionTitle title = SectionTitle.generateH2Title(this.title);
121         title.addStyleName("ks-layout-header");
122         HTML htmlLabel = new HTML("<b>All comments posted here will be visible to authors, and " +
123         		"to reviewers after you submit the proposal.</b>");
124         title.setStyleName("cluProposalTitleSection");
125         proposalTitle.setVisible(false);
126         contentPanel.add(proposalTitle);
127         contentPanel.add(title);
128         contentPanel.add(htmlLabel);
129         
130         // comments section title
131         SectionTitle leaveACommentTitle = SectionTitle.generateH3Title("Leave a Comment");
132         leaveACommentTitle.getElement().getStyle().setProperty("borderBottom", "1px solid #D8D8D8");
133         leaveACommentTitle.getElement().getStyle().setProperty("marginTop", "2em");
134         contentPanel.add(leaveACommentTitle);
135         
136         // comments section
137         HTML loggedInAsLabel = new HTML("<b>Logged in as:<b/>");
138         loggedInLabelsPanel.add(loggedInAsLabel);
139         final String userId = Application.getApplicationContext().getUserId();
140         commentServiceAsync.getUserRealName(userId, new AsyncCallback<String>() {
141             @Override
142             public void onFailure(Throwable caught) {
143                 loggedInUserNameHTML.setHTML("<b>" + userId + "</b>");
144             }
145             @Override
146             public void onSuccess(String result) {
147                 if (result != null && !result.isEmpty()) {
148                     loggedInUserNameHTML.setHTML("<b>" + result + "</b>");
149                 } else {
150                     loggedInUserNameHTML.setHTML("<b>" + userId + "</b>");
151                 }
152             }
153         });
154         
155         loggedInUserId = userId;
156         loggedInLabelsPanel.add(loggedInUserNameHTML);
157         commentTextArea.setSize("500", "100");
158         commentEditPanel.add(commentTextArea);
159         FlowPanel buttonsPanel = new FlowPanel();
160         buttonsPanel.add(cancelEditButton);
161         cancelEditButton.addClickHandler(new ClickHandler() {
162             @Override
163             public void onClick(ClickEvent event) {
164                 setEditMode(EditMode.ADD_COMMENT);
165             }
166         });
167         buttonsPanel.add(submitCommentButton);
168         submitCommentButton.setEnabled(false);
169         commentEditPanel.add(buttonsPanel);
170         buttonsPanel.addStyleName("KS-Comment-Button-Panel");
171         
172         commentTextArea.addKeyUpHandler(new KeyUpHandler() {
173             @Override
174             public void onKeyUp(KeyUpEvent event) {
175                 submitCommentButton.setEnabled(true);
176             }
177         });
178         
179         // if edit mode is add coment call addComment
180         // if edit mode is edit comment call updateComment
181         submitCommentButton.addClickHandler(new ClickHandler() {
182             @Override
183             public void onClick(ClickEvent event) {
184                 switch (editMode) {
185                     case ADD_COMMENT: {
186                         CommentInfo newComment = new CommentInfo();
187 
188                         RichTextInfo text = new RichTextInfo();
189                         text.setFormatted(commentTextArea.getText());
190                         text.setPlain(commentTextArea.getText());
191                         newComment.setType(commentTypeKey);
192                         newComment.setReferenceId(referenceId);
193                         newComment.setReferenceTypeKey(referenceTypeKey);
194                         newComment.setState(DtoState.ACTIVE.toString());
195                         newComment.setCommentText(text);
196 
197                         try {
198                             commentServiceAsync.addComment(referenceId, referenceTypeKey, newComment, new KSAsyncCallback<CommentInfo>(){
199 
200                                 @Override
201                                 public void handleFailure(Throwable caught) {
202                                     GWT.log("Add Comment Failed", caught);
203                                 }
204 
205                                 @Override
206                                 public void onSuccess(CommentInfo result) {
207                                     refreshComments();
208                                 }
209                             });
210                         } catch (Exception e) {
211                             GWT.log("Add Comment Failed", e);
212                         }
213                         break;
214                     }
215                     case UPDATE_COMMENT: {
216                         if (selectedComment != null) {
217                             RichTextInfo text = new RichTextInfo();
218                             text.setFormatted(commentTextArea.getText());
219                             text.setPlain(commentTextArea.getText());
220                             selectedComment.setReferenceId(referenceId);
221                             selectedComment.setReferenceTypeKey(referenceTypeKey);
222                             selectedComment.setCommentText(text);
223 //                            selectedComment.setType("commentType." + referenceType + "." + referenceState);
224                             selectedComment.setType(commentTypeKey);
225                         }
226 
227                         try {
228                             commentServiceAsync.updateComment(referenceId, referenceTypeKey, selectedComment, new KSAsyncCallback<CommentInfo>(){
229 
230                                 @Override
231                                 public void handleFailure(Throwable caught) {
232                                     GWT.log("Add Comment Failed", caught);
233                                 }
234 
235                                 @Override
236                                 public void onSuccess(CommentInfo result) {
237                                     refreshComments();
238                                     setEditMode(EditMode.ADD_COMMENT);
239                                 }
240                             });
241                         } catch (Exception e) {
242                             GWT.log("Add Comment Failed", e);
243                         }
244                         break;
245                     }
246                 }
247             }
248         });
249         
250         HorizontalPanel commentSectionPanel = new HorizontalPanel();
251         commentSectionPanel.add(loggedInLabelsPanel);
252         commentSectionPanel.add(commentEditPanel);
253         commentSectionPanel.add(notAuthorizedToAddComments);
254         contentPanel.add(commentSectionPanel);
255         
256         // comments table
257         contentPanel.add(commentsTableLayout);
258         
259         
260 //        scrollPanel.setHeight(height)
261         
262         commentLightBox.setWidget(contentPanel);
263         setEditMode(EditMode.ADD_COMMENT);
264     }
265     
266     private void checkPermissionsAndRedrawTable(final List<CommentInfo> commentInfos) {
267         // check permission to see if user can comment
268         commentServiceAsync.isAuthorizedAddComment(referenceId, referenceTypeKey, new KSAsyncCallback<Boolean>() {
269 
270             @Override
271             public void onFailure(Throwable caught) {
272                 GWT.log("Error checking permission for adding comments: ", caught);
273                 throw new RuntimeException("Error checking Permissions: ", caught);
274             }
275 
276             @Override
277             public void onSuccess(Boolean result) {
278                 GWT.log("User is " + ((result) ? "" : "not ") + 
279                         "authorized to add comment.", null);
280                 if(referenceId != null && !(referenceId.isEmpty())){
281                     notAuthorizedToAddComments.setVisible(false);
282                     commentEditPanel.setVisible(result);
283                     commentsTableLayout.setVisible(true);
284                     redrawCommentsTable(commentInfos);
285                 }
286                 else{
287                     notAuthorizedToAddComments.setVisible(true);
288                     commentEditPanel.setVisible(false);
289                     commentsTableLayout.setVisible(false);
290                 }
291             }
292 
293         });
294     }
295     
296     private void redrawCommentsTable(List<CommentInfo> commentInfos) {
297         commentsTableLayout.clear();
298         editControlsCallbacks.clear();
299         
300         if (commentInfos != null) {
301             int rowIndex = 0;
302             int commentCounter = 0;
303             for (final CommentInfo commentInfo : commentInfos) {
304                 int columnIndex = 0;
305                 if (commentInfo.getType() != null && 
306                         commentInfo.getType().startsWith("kuali.comment.type.workflowDecisionRationale")) {
307                     // do not display comments for workflow decision rationale.
308                     continue;
309                 }
310                 if (rowIndex == 0) {
311                     StringBuilder titleTextSb = new StringBuilder();
312                     titleTextSb.append("Comments (").append(commentInfos.size()).append(")");
313                     SectionTitle commentsSectionHeader = SectionTitle.generateH3Title(titleTextSb.toString());
314                     commentsSectionHeader.getElement().getStyle().setProperty("borderBottom", "1px solid #D8D8D8");
315                     commentsTableLayout.setWidget(rowIndex, columnIndex, commentsSectionHeader);
316                     commentsTableLayout.getFlexCellFormatter().setColSpan(rowIndex, columnIndex, 3);
317                     rowIndex++;
318                 }
319                 if (commentCounter > 0) {
320                     VerticalFlowPanel space = new VerticalFlowPanel();
321                     space.getElement().getStyle().setPaddingBottom(5d, Style.Unit.PX);
322                     commentsTableLayout.setWidget(rowIndex, columnIndex, space);
323                     commentsTableLayout.getFlexCellFormatter().setColSpan(rowIndex, columnIndex, 3);
324                     rowIndex++;
325                 }
326                 VerticalFlowPanel userNameAndTime = new VerticalFlowPanel();
327                 final HTML userNameLabel = new HTML();
328                 // TODO use user id for now change to user name
329                 final String userId = commentInfo.getMetaInfo().getUpdateId();
330                 commentServiceAsync.getUserRealName(userId, new AsyncCallback<String>() {
331                     @Override
332                     public void onFailure(Throwable caught) {
333                         userNameLabel.setHTML("<b>" + userId + "</b>");
334                     }
335                     @Override
336                     public void onSuccess(String result) {
337                         if (result != null && !result.isEmpty()) {
338                             userNameLabel.setHTML("<b>" + result + "</b>");
339                         } else {
340                             userNameLabel.setHTML("<b>" + userId + "</b>");
341                         }
342                     }
343                 });
344                 Date createTime = commentInfo.getMetaInfo().getCreateTime();
345                 userNameAndTime.add(userNameLabel);
346                 userNameAndTime.add(new KSLabel(df.format(createTime)));
347                 userNameAndTime.getElement().getStyle().setPaddingRight(20d, Style.Unit.PX);
348                 commentsTableLayout.setWidget(rowIndex, columnIndex, userNameAndTime);
349                 columnIndex++;
350                 
351                 RichTextInfo commentRT = commentInfo.getCommentText();
352                 String commentText = commentRT.getPlain();
353                 KSLabel commentTextLabel = new KSLabel(commentText);
354                 commentTextLabel.getElement().getStyle().setPaddingRight(20d, Style.Unit.PX);
355                 commentTextLabel.setWidth("120px");
356                 commentTextLabel.getElement().getStyle().setProperty("wordWrap", "break-word");
357                 commentsTableLayout.setWidget(rowIndex, columnIndex, commentTextLabel);
358                 columnIndex++;
359                 
360                 final KSButton editButton = new KSButton("Edit", ButtonStyle.DEFAULT_ANCHOR);
361                 final KSButton deleteButton = new KSButton("Delete", ButtonStyle.DEFAULT_ANCHOR);
362                 editButton.getElement().getStyle().setPadding(5d, Style.Unit.PX);
363                 editControlsCallbacks.add(new Callback<EditMode>() {
364                     @Override
365                     public void exec(EditMode result) {
366                         switch (editMode) {
367                             case UPDATE_COMMENT:
368 //                                editButton.setStyleName("KS-CommentButtonDisabled");
369 //                                deleteButton.setStyleName("KS-CommentButtonDisabled");
370                                 editButton.setEnabled(false);
371                                 deleteButton.setEnabled(false);
372                                 break;
373                             case ADD_COMMENT:
374 //                                editButton.setStyleName("KS-CommentButton");
375 //                                deleteButton.setStyleName("KS-CommentButton");
376                                 editButton.setEnabled(true);
377                                 deleteButton.setEnabled(true);
378                                 break;
379                         }
380                     }
381                 });
382                 
383                 editButton.addClickHandler(new ClickHandler() {
384                     @Override
385                     public void onClick(ClickEvent event) {
386                         String commentText = (commentInfo == null ||
387                                 commentInfo.getCommentText() == null)? "" :
388                                     commentInfo.getCommentText().getPlain();
389                         selectedComment = commentInfo;
390                         commentTextArea.setText(commentText);
391                         commentTextArea.setFocus(true);
392                         setEditMode(EditMode.UPDATE_COMMENT);
393                     }
394                 });
395                 deleteButton.addClickHandler(new ClickHandler() {
396                     @Override
397                     public void onClick(ClickEvent event) {
398                             final ConfirmationDialog confirmDeletion =
399                                 new ConfirmationDialog("Delete Comment",  
400                                     "You are about to delete a comment.  Are you sure?");
401                             confirmDeletion.getConfirmButton().addClickHandler(new ClickHandler(){
402                                 @Override
403                                 public void onClick(ClickEvent event) {
404                                     try {
405                                         commentServiceAsync.removeComment(commentInfo.getId(), 
406                                                 referenceId, referenceTypeKey, 
407                                                 new KSAsyncCallback<StatusInfo>(){
408 
409                                             @Override
410                                             public void handleFailure(Throwable caught) {
411                                                 GWT.log("remove Comment Failed", caught);
412                                             }
413 
414                                             @Override
415                                             public void onSuccess(StatusInfo result) {
416                                                 confirmDeletion.hide();
417                                                 refreshComments();
418                                             }
419 
420                                         });
421                                     } catch (Exception e) {
422                                         GWT.log("remove Comment Failed", e);
423                                     }
424                                 }
425                             });
426                             confirmDeletion.show();
427                     }
428                 });
429                 commentsTableLayout.setWidget(rowIndex, columnIndex, editButton);
430                 columnIndex++;
431                 commentsTableLayout.setWidget(rowIndex, columnIndex, deleteButton);
432                 columnIndex++;
433                 if (userId == null || !userId.equals(this.loggedInUserId)) {
434                     editButton.setVisible(false);
435                     deleteButton.setVisible(false);
436                 }
437                 
438                 rowIndex++;
439                 
440                 commentCounter++;
441             }
442             setEditMode(EditMode.ADD_COMMENT);
443         }
444     }
445     
446     public void setEditMode(EditMode editMode) {
447         this.editMode = editMode;
448         switch (editMode) {
449             case UPDATE_COMMENT:
450                 cancelEditButton.setVisible(true);
451                 if (editControlsCallbacks != null) {
452                     for (Callback<EditMode> callback : editControlsCallbacks) {
453                         callback.exec(EditMode.UPDATE_COMMENT);
454                     }
455                 }
456                 break;
457             case ADD_COMMENT:
458                 cancelEditButton.setVisible(false);
459                 commentTextArea.setText("");
460                 if (editControlsCallbacks != null) {
461                     for (Callback<EditMode> callback : editControlsCallbacks) {
462                         callback.exec(EditMode.ADD_COMMENT);
463                     }
464                 }
465                 break;
466         }
467     }
468     
469     public void refreshComments(){
470         //rpc call to get all current comments and populate into comment list
471         try {
472             commentServiceAsync.getComments(referenceId, referenceTypeKey, new KSAsyncCallback<List<CommentInfo>>(){
473 
474                 @Override
475                 public void handleFailure(Throwable caught) {
476                     GWT.log("getComments failed", caught);
477                 }
478 
479                 @Override
480                 public void onSuccess(List<CommentInfo> result) {
481                     if (result != null && !result.isEmpty()) {
482                         Collections.sort(result, new Comparator<CommentInfo>(){
483 
484                             @Override
485                             public int compare(CommentInfo comment1, CommentInfo comment2) {
486 
487                                 if(comment1.getMetaInfo().getCreateTime().after(comment2.getMetaInfo().getCreateTime())){
488                                     return -1;
489                                 }
490                                 else if(comment1.getMetaInfo().getCreateTime().before(comment2.getMetaInfo().getCreateTime())){
491                                     return 1;
492                                 }
493                                 else{
494                                     //equal
495                                     return 0;
496                                 }
497 
498                             }
499                         });
500                     }
501                     checkPermissionsAndRedrawTable(result);
502                 }
503             });
504         } catch (Exception e) {
505             Window.alert("Failed to refresh Comments");
506             GWT.log("refresh Comments Failed",e);
507         }
508 
509 
510     }
511 //    private void redrawCommentsTable(FlexTable tableLayout) {
512 //        StringBuilder titleTextSb = new StringBuilder();
513 //        titleTextSb.append("Comments (").append(docInfos.size()).append(")");
514 //        SectionTitle uploadedFileSectionHeader = SectionTitle.generateH3Title(titleTextSb.toString());
515 //        uploadedFileSectionHeader.getElement().getStyle().setProperty("borderBottom", "1px solid #D8D8D8");
516 //        tableLayout.setWidget(rowIndex, columnIndex, uploadedFileSectionHeader);
517 //        tableLayout.getFlexCellFormatter().setColSpan(rowIndex, columnIndex, 3);
518 //    }
519     
520     @Override
521     public String getReferenceId() {
522         return referenceId;
523     }
524 
525     @Override
526     public String getReferenceState() {
527         return referenceState;
528     }
529 
530     @Override
531     public String getReferenceType() {
532         return referenceType;
533     }
534 
535     @Override
536     public String getReferenceTypeKey() {
537         return referenceTypeKey;
538     }
539 
540     @Override
541     public void setReferenceId(String id) {
542         this.referenceId = id;
543     }
544 
545     @Override
546     public void setReferenceState(String state) {
547         this.referenceState = state;
548     }
549 
550     @Override
551     public void setReferenceType(String type) {
552         this.referenceType = type;
553     }
554 
555     @Override
556     public void setReferenceTypeKey(String key) {
557         this.referenceTypeKey = key;
558     }
559     
560     public void setReferenceAttributes(Map<String, String> referenceAttributes) {
561         this.referenceAttributes = referenceAttributes;
562     }
563     
564     public void show() {
565         controller.requestModel(ReferenceModel.class, 
566                 new ModelRequestCallback<ReferenceModel>(){
567             public void onModelReady(ReferenceModel model) {
568                 String proposalTitleString = null;
569                 setReferenceId(model.getReferenceId());
570                 setReferenceTypeKey(model.getReferenceTypeKey());
571                 setReferenceType(model.getReferenceType());
572                 setReferenceState(model.getReferenceState());
573                 setReferenceAttributes(model.getReferenceAttributes());
574                 proposalTitleString = (model.getReferenceAttributes() == null)? null : 
575                     model.getReferenceAttributes().get("name");
576                 if (proposalTitleString != null && !proposalTitleString.trim().isEmpty()) {
577                     proposalTitle.setText(proposalTitleString);
578                     proposalTitle.setVisible(true);
579                 } else {
580                     proposalTitle.setText("");
581                     proposalTitle.setVisible(false);
582                 }
583                 refreshComments();
584                 commentLightBox.show();
585             }
586 
587             public void onRequestFail(Throwable cause) {
588                 Window.alert(cause.toString());
589             }
590         });
591     }
592 
593 }