package com.kenai.redminenb.issue; import com.kenai.redminenb.Redmine; import com.kenai.redminenb.timetracker.IssueTimeTrackerTopComponent; import com.kenai.redminenb.ui.Defaults; import com.kenai.redminenb.util.RedmineUtil; import com.taskadapter.redmineapi.bean.Issue; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.net.URL; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.netbeans.modules.bugtracking.spi.IssueController; import org.openide.awt.HtmlBrowser; import org.openide.util.HelpCtx; import org.openide.util.Mutex; import org.openide.util.NbBundle; /** * * @author Mykolas * @author Anchialas <anchialas@gmail.com> */ public class RedmineIssueController implements IssueController { private final RedmineIssue redmineIssue; private final JComponent component; private final RedmineIssuePanel issuePanel; private Action viewWatchers; public RedmineIssueController(RedmineIssue issue) { this.redmineIssue = issue; issuePanel = new RedmineIssuePanel(issue); initActions(); initListeners(); JScrollPane scrollPane = new JScrollPane(issuePanel); scrollPane.setBorder(null); scrollPane.getVerticalScrollBar().setUnitIncrement(20); JPanel pane = new JPanel(new BorderLayout()); pane.setBorder(null); pane.setBackground(UIManager.getDefaults().getColor("EditorPane.background")); pane.add(scrollPane, BorderLayout.CENTER); component = pane; redmineIssue.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if("busy".equals(evt.getPropertyName())) { issuePanel.enableFields(! ((boolean)evt.getNewValue())); } else if (org.netbeans.modules.bugtracking.api.Issue.EVENT_ISSUE_DATA_CHANGED.equals(evt.getPropertyName())) { issuePanel.customFieldValueBackingStore.clear(); issuePanel.initIssue(); } } }); } @Override public JComponent getComponent() { return component; } @Override public void opened() { if (redmineIssue != null) { issuePanel.opened(); redmineIssue.opened(); redmineIssue.getRepository().getRequestProcessor().execute(new Runnable() { @Override public void run() { redmineIssue.refresh(); issuePanel.initIssue(); } }); viewWatchers.setEnabled(redmineIssue.getRepository().isFeatureWatchers()); } } @Override public void closed() { if (redmineIssue != null) { redmineIssue.closed(); issuePanel.closed(); } } @Override public HelpCtx getHelpCtx() { return new HelpCtx(getClass().getName()); } private RedmineIssue createSubTask() { Issue issue = redmineIssue.getIssue(); // TODO: check if issue is available (id != 0) Issue subIssue = new Issue(); subIssue.setParentId(issue.getId()); subIssue.setAssigneeId(issue.getAssigneeId()); //subIssue.setAuthor(issue.getAuthor()); subIssue.setAuthorId(redmineIssue.getRepository().getCurrentUser().getId()); subIssue.setCategory(issue.getCategory()); subIssue.setPriorityId(issue.getPriorityId()); subIssue.setTargetVersion(issue.getTargetVersion()); subIssue.setTracker(issue.getTracker()); subIssue.setStatusId(issue.getStatusId()); subIssue.setDoneRatio(0); subIssue.setSubject("New Subtask"); return new RedmineIssue(redmineIssue.getRepository(), subIssue); } private void initListeners() { abstract class DelegateChangeHandler implements DocumentListener { @Override public void insertUpdate(DocumentEvent e) { changedUpdate(e); } @Override public void removeUpdate(DocumentEvent e) { changedUpdate(e); } }; issuePanel.descTextArea.getDocument().addDocumentListener(new DelegateChangeHandler() { @Override public void changedUpdate(DocumentEvent e) { issuePanel.updateTextileOutput(); } }); issuePanel.updateCommentTextArea.getDocument().addDocumentListener(new DelegateChangeHandler() { @Override public void changedUpdate(DocumentEvent e) { issuePanel.updateCommentTextileOutput(); } }); } @NbBundle.Messages({ "CTL_RefreshAction=Refresh", "CTL_ShowInBrowserAction=Show in Browser", "CTL_CreateSubTaskAction=Create Subtask", "CTL_ActionListAction.add=Add to Action Items", "CTL_ActionListAction.remove=Remove from Action Items", "CTL_OpenIssueForTimeTracking=Open Timetracker with Issue", "CTL_OpenWatchersList=Open Watchers List" }) private void initActions() { Action timeTrackingAction = new AbstractAction(Bundle.CTL_OpenIssueForTimeTracking(), Defaults.getIcon("appointment-new.png")) { @Override public void actionPerformed(ActionEvent e) { IssueTimeTrackerTopComponent.getInstance().open(); IssueTimeTrackerTopComponent.getInstance().setIssue(redmineIssue); } }; Action refreshAction = new AbstractAction(Bundle.CTL_RefreshAction(), Defaults.getIcon("refresh.png")) { @Override public void actionPerformed(ActionEvent e) { new SwingWorker() { @Override protected Object doInBackground() throws Exception { redmineIssue.refresh(); issuePanel.initIssue(); return null; } @Override protected void done() { issuePanel.setInfoMessage("Issue successfully reloaded."); } }.execute(); } }; Action showInBrowserAction = new AbstractAction(Bundle.CTL_ShowInBrowserAction(), Defaults.getIcon("redmine.png")) { @Override public void actionPerformed(ActionEvent e) { try { URL url = new URL(redmineIssue.getRepository().getUrl() + "/issues/" + redmineIssue.getID()); // NOI18N HtmlBrowser.URLDisplayer.getDefault().showURL(url); } catch (IOException ex) { Redmine.LOG.log(Level.INFO, "Unable to show the issue in the browser.", ex); // NOI18N } } }; Action createSubTaskAction = new AbstractAction(Bundle.CTL_CreateSubTaskAction(), Defaults.getIcon("subtask.png")) { @Override public void actionPerformed(ActionEvent e) { RedmineIssue subTask = createSubTask(); RedmineUtil.openIssue(subTask); } }; viewWatchers = new AbstractAction(Bundle.CTL_OpenWatchersList(), Defaults.getIcon("face-glasses.png")) { @Override public void actionPerformed(ActionEvent e) { WatcherEditor we = new WatcherEditor(redmineIssue); we.run(); } }; viewWatchers.setEnabled(redmineIssue.getRepository().isFeatureWatchers()); issuePanel.addToolbarAction(viewWatchers, false); issuePanel.addToolbarAction(timeTrackingAction, false); issuePanel.addToolbarAction(showInBrowserAction, false); issuePanel.addToolbarAction(createSubTaskAction, false); issuePanel.addToolbarAction(refreshAction, false); } private final PropertyChangeSupport support = new PropertyChangeSupport(this); @Override public boolean saveChanges() { // @todo: Clean this up - the logic of issue handling has to be moved // from the panel into the controller... Mutex.EVENT.writeAccess(new Runnable() { @Override public void run() { issuePanel.saveIssue(); } }); return true; } @Override public boolean discardUnsavedChanges() { if(issuePanel != null) { redmineIssue.getRepository().getRequestProcessor().execute(new Runnable() { public void run() { issuePanel.initIssue(); } }); } return true; } @Override public boolean isChanged() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public void addPropertyChangeListener(PropertyChangeListener pl) { support.addPropertyChangeListener(pl); } @Override public void removePropertyChangeListener(PropertyChangeListener pl) { support.removePropertyChangeListener(pl); } }