package org.nightlabs.jfire.issuetracking.ui.issue;
import java.text.DateFormat;
import java.util.HashMap;
import java.util.Map;
import javax.jdo.FetchPlan;
import javax.jdo.JDOHelper;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.statushandlers.StatusManager;
import org.nightlabs.base.ui.editor.JDOObjectEditorInput;
import org.nightlabs.base.ui.job.Job;
import org.nightlabs.base.ui.notification.SelectionManager;
import org.nightlabs.base.ui.resource.SharedImages;
import org.nightlabs.base.ui.util.RCPUtil;
import org.nightlabs.jdo.NLJDOHelper;
import org.nightlabs.jfire.base.jdo.GlobalJDOManagerProvider;
import org.nightlabs.jfire.base.login.ui.Login;
import org.nightlabs.jfire.base.login.ui.part.LSDViewPart;
import org.nightlabs.jfire.issue.Issue;
import org.nightlabs.jfire.issue.IssueComment;
import org.nightlabs.jfire.issue.dao.IssueCommentDAO;
import org.nightlabs.jfire.issue.dao.IssueDAO;
import org.nightlabs.jfire.issue.id.IssueCommentID;
import org.nightlabs.jfire.issue.id.IssueID;
import org.nightlabs.jfire.issuetracking.ui.IssueTrackingPlugin;
import org.nightlabs.jfire.issuetracking.ui.issue.editor.IssueEditor;
import org.nightlabs.jfire.issuetracking.ui.issue.editor.IssueEditorInput;
import org.nightlabs.jfire.issuetracking.ui.resource.Messages;
import org.nightlabs.jfire.security.User;
import org.nightlabs.notification.NotificationAdapterCallerThread;
import org.nightlabs.notification.NotificationEvent;
import org.nightlabs.notification.NotificationListener;
import org.nightlabs.progress.ProgressMonitor;
/**
* @author Chairat Kongarayawetchakun <!-- chairat [AT] nightlabs [DOT] de -->
*
*/
public class IssueCommentView
extends LSDViewPart
{
public static final String VIEW_ID = IssueCommentView.class.getName();
private FormToolkit toolkit;
private ScrolledForm scrolledForm;
private Composite body;
private static DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
// private IMemento initMemento = null;
/* (non-Javadoc)
* @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento)
*/
// @Override
// public void init(IViewSite site, IMemento memento) throws PartInitException {
// super.init(site, memento);
// this.initMemento = memento;
// }
// private Composite parent;
/* (non-Javadoc)
* @see org.nightlabs.base.ui.part.ControllablePart#createPartContents(org.eclipse.swt.widgets.Composite)
*/
private User user;
@Override
public void createPartContents(Composite parent)
{
// this.parent = parent;
contributeToActionBars();
Job job = new Job(Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.loadUserJob.text")) { //$NON-NLS-1$
@Override
protected IStatus run(ProgressMonitor monitor) throws Exception {
monitor.beginTask("Loading login user", 100);
user = Login.sharedInstance().getUser(null, NLJDOHelper.MAX_FETCH_DEPTH_NO_LIMIT, monitor);
monitor.done();
return Status.OK_STATUS;
}
};
job.setPriority(Job.SHORT);
job.schedule();
toolkit = new FormToolkit(parent.getDisplay());
scrolledForm = toolkit.createScrolledForm(parent);
scrolledForm.setText(Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.scrolledForm.noIssue.text")); //$NON-NLS-1$
scrolledForm.setBackground(null);
body = scrolledForm.getBody();
body.setBackground(null);
GridLayout layout = new GridLayout(4, false);
body.setLayout(layout);
SelectionManager.sharedInstance().addNotificationListener(IssueTrackingPlugin.ZONE_PROPERTY, Issue.class, issueSelectionListener);
try{
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().addPartListener(partListener);
}catch(Exception e){
StatusManager.getManager().handle(
new Status(Status.ERROR, IssueTrackingPlugin.PLUGIN_ID, "Excxeption adding part listener!", e), //$NON-NLS-1$
StatusManager.LOG);
}
scrolledForm.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
SelectionManager.sharedInstance().removeNotificationListener(IssueTrackingPlugin.ZONE_PROPERTY, Issue.class, issueSelectionListener);
}
});
final JDOListenerAccessor accessor = new JDOListenerAccessor();
GlobalJDOManagerProvider.sharedInstance().getLifecycleManager().addLifecycleListener(accessor.issueCommentAddNotificationListener);
scrolledForm.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent event) {
GlobalJDOManagerProvider.sharedInstance().getLifecycleManager().removeLifecycleListener(accessor.issueCommentAddNotificationListener);
}
});
}
class JDOListenerAccessor {
private org.nightlabs.jfire.base.jdo.notification.JDOLifecycleListener issueCommentAddNotificationListener = new org.nightlabs.jfire.base.ui.jdo.notification.JDOLifecycleAdapterJob("Loading Issue") {
private org.nightlabs.jfire.jdo.notification.IJDOLifecycleListenerFilter filter = new org.nightlabs.jfire.jdo.notification.SimpleLifecycleListenerFilter(
IssueComment.class,
false,
org.nightlabs.jfire.jdo.notification.JDOLifecycleState.NEW,
org.nightlabs.jfire.jdo.notification.JDOLifecycleState.DELETED);
public org.nightlabs.jfire.jdo.notification.IJDOLifecycleListenerFilter getJDOLifecycleListenerFilter()
{
return filter;
}
public void notify(org.nightlabs.jfire.base.jdo.notification.JDOLifecycleEvent event)
{
ProgressMonitor monitor = getProgressMonitor();
monitor.beginTask("Reloading Data...", 100);
reloadIssue();
monitor.done();
}
};
}
public void reloadIssue() {
Job job = new Job("Loading Issue...") {
@Override
protected IStatus run(ProgressMonitor monitor) throws Exception {
if (issueID == null){
return new Status(Status.WARNING, IssueTrackingPlugin.PLUGIN_ID, "Issue ID is null! Can't reload issue!"); //$NON-NLS-1$
}
final Issue issue = IssueDAO.sharedInstance().getIssue(issueID, FETCH_GROUP_ISSUE, NLJDOHelper.MAX_FETCH_DEPTH_NO_LIMIT, monitor);
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
scrolledForm.setText(Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.scrolledForm.issue.text") + issue.getIssueID() + " - " + issue.getSubject().getText()); //$NON-NLS-1$ //$NON-NLS-2$
createComments(issue);
}
});
return Status.OK_STATUS;
}
};
job.schedule();
}
/* (non-Javadoc)
* @see org.nightlabs.jfire.base.ui.login.part.LSDViewPart#setFocus()
*/
@Override
public void setFocus() {
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento)
*/
@Override
public void saveState(IMemento memento) {
super.saveState(memento);
}
private static String[] FETCH_GROUP_ISSUE = new String[] {
FetchPlan.DEFAULT,
Issue.FETCH_GROUP_ISSUE_COMMENTS,
Issue.FETCH_GROUP_SUBJECT,
IssueComment.FETCH_GROUP_USER,
IssueComment.FETCH_GROUP_ISSUE};
private IssueID issueID;
private NotificationListener issueSelectionListener = new NotificationAdapterCallerThread(){
public void notify(NotificationEvent notificationEvent) {
Object firstSelection = notificationEvent.getFirstSubject();
if (firstSelection instanceof IssueID
&& !firstSelection.equals(issueID)) {
issueID = (IssueID) firstSelection;
reloadIssue();
}
}
};
private IPartListener partListener = new IPartListener() {
@Override
public void partOpened(IWorkbenchPart part) {
getIssueID(part);
}
@Override
public void partBroughtToTop(IWorkbenchPart part) {
getIssueID(part);
}
@Override
public void partActivated(IWorkbenchPart part) {
getIssueID(part);
}
@SuppressWarnings("unchecked")
private void getIssueID(IWorkbenchPart part){
if (part instanceof IssueEditor){
IssueEditor issueEditor = (IssueEditor) part;
if (issueEditor.getEditorInput() instanceof IssueEditorInput){
IssueID issueID = ((JDOObjectEditorInput<IssueID>) issueEditor.getEditorInput()).getJDOObjectID();
if (issueID != null
&& !issueID.equals(IssueCommentView.this.issueID)){
IssueCommentView.this.issueID = issueID;
reloadIssue();
}
}
}
}
@Override
public void partDeactivated(IWorkbenchPart arg0) {
// do nothing
}
@Override
public void partClosed(IWorkbenchPart arg0) {
// do nothing
}
};
private void createComments(final Issue issue) {
for (Control child : body.getChildren()) {
child.dispose();
}
for (final IssueComment comment : issue.getComments()) {
createCommentEntry(body, comment);
}
scrolledForm.reflow(true);
}
private static Color reportBackgroundColor = new Color(Display.getCurrent(), 200, 200, 232);
private static Color commentBackgroundColor = new Color(Display.getCurrent(), 232, 232, 232);
private Map<Long, Text> commentMap = new HashMap<Long, Text>();
private void createCommentEntry(final Composite body, final IssueComment comment) {
/**Reporter**/
Composite reporterComposite = toolkit.createComposite(body);
GridLayout gridLayout = new GridLayout(1, false);
reporterComposite.setLayout(gridLayout);
reporterComposite.setBackground(reportBackgroundColor);
//Label
Hyperlink idLink = toolkit.createHyperlink(reporterComposite, "(" + Long.toString(comment.getCommentID()) + ")", SWT.NONE); //$NON-NLS-1$ //$NON-NLS-2$
idLink.setBackground(reportBackgroundColor);
GridData gridData = new GridData();
idLink.setLayoutData(gridData);
Hyperlink userNameLink = toolkit.createHyperlink(reporterComposite, comment.getUser().getName(), SWT.NONE);
userNameLink.setBackground(reportBackgroundColor);
gridData = new GridData();
userNameLink.setLayoutData(gridData);
Label timeLabel = toolkit.createLabel(reporterComposite, dateTimeFormat.format(comment.getCreateTimestamp()));
timeLabel.setBackground(reportBackgroundColor);
gridData = new GridData();
timeLabel.setLayoutData(gridData);
//Actions
if (user.getUserID().equals(comment.getUser().getUserID())) {
Composite actionComposite = toolkit.createComposite(reporterComposite);
actionComposite.setLayout(new GridLayout(3, false));
actionComposite.setBackground(reportBackgroundColor);
gridData = new GridData();
actionComposite.setLayoutData(gridData);
//Images
ImageHyperlink editLink = toolkit.createImageHyperlink(actionComposite, SWT.NONE);
editLink.setImage(SharedImages.EDIT_16x16.createImage(scrolledForm.getShell().getDisplay()));
editLink.setHoverImage(SharedImages.EDIT_24x24.createImage(scrolledForm.getShell().getDisplay()));
editLink.setBackground(reportBackgroundColor);
editLink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
IssueCommentEditDialog dialog = new IssueCommentEditDialog(RCPUtil.getActiveShell(), comment);
int result = dialog.open();
if (result == Dialog.OK) {
Text t = commentMap.get(comment.getCommentID());
t.setText(comment.getText());
scrolledForm.layout(true, true);
scrolledForm.reflow(true);
}
}
});
ImageHyperlink deleteLink = toolkit.createImageHyperlink(actionComposite, SWT.NONE);
deleteLink.setImage(SharedImages.DELETE_16x16.createImage());
deleteLink.setHoverImage(SharedImages.DELETE_24x24.createImage());
deleteLink.setBackground(reportBackgroundColor);
deleteLink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
boolean result = MessageDialog.openConfirm(
RCPUtil.getActiveShell(),
Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.confirmDelete.title"), //$NON-NLS-1$
Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.confirmDelete.description")); //$NON-NLS-1$
if (result) {
Job deleteIssueJob = new Job(Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.deleteCommentJob") + comment.getCommentID()) { //$NON-NLS-1$
@Override
protected IStatus run(ProgressMonitor monitor) {
monitor.beginTask("Deleting comment", 100);
IssueCommentDAO.sharedInstance().deleteIssueComment((IssueCommentID)JDOHelper.getObjectId(comment), monitor);
monitor.done();
return Status.OK_STATUS;
}
};
deleteIssueJob.setPriority(Job.SHORT);
deleteIssueJob.schedule();
}
}
});
ImageHyperlink printLink = toolkit.createImageHyperlink(actionComposite, SWT.NONE);
printLink.setImage(SharedImages.PRINT_16x16.createImage());
printLink.setHoverImage(SharedImages.PRINT_24x24.createImage());
printLink.setBackground(reportBackgroundColor);
}
gridData = new GridData(GridData.FILL_VERTICAL);
gridData.horizontalSpan = 1;
reporterComposite.setLayoutData(gridData);
/**Detail**/
Composite textComposite = toolkit.createComposite(body);
textComposite.setLayout(new GridLayout(3, false));
textComposite.setBackground(commentBackgroundColor);
//Label
Text text = toolkit.createText(textComposite, comment.getText(), SWT.WRAP);
text.setBackground(commentBackgroundColor);
commentMap.put(comment.getCommentID(), text);
gridData = new GridData(GridData.FILL_BOTH);
gridData.horizontalSpan = 3;
textComposite.setLayoutData(gridData);
}
/*private URL url = FileLocator.find(IssueTrackingPlugin.getDefault().getBundle(), new Path("default.css"), null);
private void createCommentsByBrowser(Issue issue) {
try {
url = FileLocator.toFileURL(url);
} catch (IOException e1) {
throw new RuntimeException(e1);
}
if (browser == null) {
browser = new Browser(body, SWT.NONE);
browser.setLayoutData(new GridData(GridData.FILL_BOTH));
browser.addLocationListener(new LocationAdapter() {
@Override
public void changing(LocationEvent event) {
int i = event.location.indexOf('#');
String value = event.location.substring(i + 1);
}
});
}
StringBuffer buf = new StringBuffer();
buf.append("<html>");
buf.append("<head><link rel=\"stylesheet\" type=\"text/css\" href=\""+ url.toString() + "\" />");
buf.append("</head><body><table class=\"width100\" cellspacing=\"1\">");
for (IssueComment comment : issue.getComments()) {
buf.append("<tr class=\"bugnote\">");
buf.append("<td class=\"bugnote-public\"");
buf.append("<span class=\"small\">" + comment.getCommentID() + "</span><br/>");
buf.append(comment.getUser().getName() + "<br />");
buf.append("<span class=\"small\">" + dateTimeFormat.format(comment.getCreateTimestamp()) + "</span><br />");
buf.append("<br /><span class=\"small\">");
buf.append("<form method=\"POST\" action=\"bugnote_edit_page.php?bugnote_id=1706\"><input type=\"submit\" class=\"button-small\" value=\"Edit\" /></form><form method=\"POST\" action=\"bugnote_delete.php?bugnote_id=1706\"><input type=\"submit\" class=\"button-small\" value=\"Delete\" /></form><form method=\"POST\" action=\"bugnote_set_view_state.php?private=1&bugnote_id=1706\"><input type=\"submit\" class=\"button-small\" value=\"Make Private\" /></form></span>");
buf.append("</td>");
buf.append("<td class=\"bugnote-note-public\">" + comment.getText() + "<br /></td>");
buf.append("</tr>");
buf.append("<tr><td class=\"spacer\" colspan=\"2\"> </td></tr>");
}
buf.append("</table></body></html>");
browser.setText(buf.toString());
scrolledForm.reflow(true);
}*/
/**
* Prepares the ActionBar.
*/
private void contributeToActionBars() {
if (addCommentAction != null)
return;
IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager();
addCommentAction = new AddCommentAction();
toolBarManager.add(addCommentAction);
toolBarManager.update(true);
}
@Override
public void dispose() {
toolkit.dispose();
super.dispose();
};
private AddCommentAction addCommentAction;
private class AddCommentAction
extends Action
{
private Issue issue = null;
public AddCommentAction() {
setId(AddCommentAction.class.getName());
setImageDescriptor(SharedImages.ADD_16x16);
setToolTipText(Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.AddCommentAction.toolTipText")); //$NON-NLS-1$
setText(Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.AddCommentAction.text")); //$NON-NLS-1$
}
@Override
public void run() {
Job loadIssueJob = new Job("Loading Issue...") {
@Override
protected IStatus run(ProgressMonitor monitor) throws Exception {
if (issueID == null){
return new Status(Status.WARNING, IssueTrackingPlugin.PLUGIN_ID, "Issue ID is null! Can't reload issue in AddCommentAction!"); //$NON-NLS-1$
}
issue = IssueDAO.sharedInstance().getIssue(issueID, FETCH_GROUP_ISSUE, NLJDOHelper.MAX_FETCH_DEPTH_NO_LIMIT, monitor);
return Status.OK_STATUS;
}
};
loadIssueJob.addJobChangeListener(new JobChangeAdapter(){
@Override
public void done(IJobChangeEvent event) {
if (Status.OK_STATUS == event.getResult() && issue != null){
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
IssueCommentAddDialog dialog = new IssueCommentAddDialog(RCPUtil.getActiveShell(), issue, user);
int result = dialog.open();
if (result == Dialog.OK) {
final IssueComment comment = new IssueComment(issue, dialog.getCommentString(), user);
Job job = new Job(Messages.getString("org.nightlabs.jfire.issuetracking.ui.issueIssueCommentView.storeCommentJob.text")) { //$NON-NLS-1$
@Override
protected IStatus run(ProgressMonitor monitor) throws Exception {
monitor.beginTask("Storing comment", 100);
IssueCommentDAO.sharedInstance().storeIssueComment(comment, false, null, 1, monitor);
monitor.done();
return Status.OK_STATUS;
}
};
job.setPriority(Job.SHORT);
job.schedule();
}
}
});
}else{
StatusManager.getManager().handle(
new Status(Status.WARNING, IssueTrackingPlugin.PLUGIN_ID, "Issue is null! Comment could not be added by AddCommentAction!"), //$NON-NLS-1$
StatusManager.LOG);
}
super.done(event);
}
});
loadIssueJob.schedule();
}
}
}