1 package com.atlassian.theplugin.idea.jira;
2
3 import com.atlassian.theplugin.cfg.CfgUtil;
4 import com.atlassian.theplugin.commons.ServerType;
5 import com.atlassian.theplugin.commons.cfg.*;
6 import com.atlassian.theplugin.commons.configuration.PluginConfiguration;
7 import com.atlassian.theplugin.commons.remoteapi.RemoteApiException;
8 import com.atlassian.theplugin.commons.remoteapi.ServerData;
9 import com.atlassian.theplugin.configuration.IssueRecentlyOpenBean;
10 import com.atlassian.theplugin.configuration.JiraFilterConfigurationBean;
11 import com.atlassian.theplugin.configuration.JiraWorkspaceConfiguration;
12 import com.atlassian.theplugin.idea.Constants;
13 import com.atlassian.theplugin.idea.IdeaHelper;
14 import com.atlassian.theplugin.idea.PluginToolWindowPanel;
15 import com.atlassian.theplugin.idea.action.issues.RunIssueActionAction;
16 import com.atlassian.theplugin.idea.action.issues.activetoolbar.ActiveIssueUtils;
17 import com.atlassian.theplugin.idea.config.ProjectCfgManagerImpl;
18 import com.atlassian.theplugin.idea.jira.tree.JIRAFilterTree;
19 import com.atlassian.theplugin.idea.jira.tree.JIRAIssueTreeBuilder;
20 import com.atlassian.theplugin.idea.jira.tree.JIRAIssueTreeNode;
21 import com.atlassian.theplugin.idea.jira.tree.JiraFilterTreeSelectionListener;
22 import com.atlassian.theplugin.idea.ui.DialogWithDetails;
23 import com.atlassian.theplugin.idea.ui.PopupAwareMouseAdapter;
24 import com.atlassian.theplugin.jira.JIRAIssueProgressTimestampCache;
25 import com.atlassian.theplugin.jira.JIRAServerFacade;
26 import com.atlassian.theplugin.jira.JIRAServerFacadeImpl;
27 import com.atlassian.theplugin.jira.api.*;
28 import com.atlassian.theplugin.jira.cache.RecentlyOpenIssuesCache;
29 import com.atlassian.theplugin.jira.model.*;
30 import com.atlassian.theplugin.remoteapi.MissingPasswordHandlerJIRA;
31 import com.atlassian.theplugin.remoteapi.MissingPasswordHandlerQueue;
32 import com.atlassian.theplugin.util.PluginUtil;
33 import com.intellij.openapi.actionSystem.*;
34 import com.intellij.openapi.application.ApplicationManager;
35 import com.intellij.openapi.application.ModalityState;
36 import com.intellij.openapi.fileEditor.FileDocumentManager;
37 import com.intellij.openapi.progress.ProgressIndicator;
38 import com.intellij.openapi.progress.ProgressManager;
39 import com.intellij.openapi.progress.Task;
40 import com.intellij.openapi.project.Project;
41 import com.intellij.openapi.util.Pair;
42 import com.intellij.openapi.vcs.changes.Change;
43 import com.intellij.openapi.vcs.changes.ChangeListManager;
44 import com.intellij.openapi.vcs.changes.LocalChangeList;
45 import com.intellij.openapi.wm.WindowManager;
46 import com.intellij.ui.TreeSpeedSearch;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
49
50 import javax.swing.*;
51 import javax.swing.Timer;
52 import javax.swing.event.DocumentEvent;
53 import javax.swing.event.DocumentListener;
54 import javax.swing.event.HyperlinkEvent;
55 import javax.swing.event.HyperlinkListener;
56 import javax.swing.tree.TreePath;
57 import java.awt.*;
58 import java.awt.event.*;
59 import java.net.MalformedURLException;
60 import java.net.URL;
61 import java.util.*;
62 import java.util.List;
63
64 public final class IssueListToolWindowPanel extends PluginToolWindowPanel implements DataProvider, IssueActionProvider {
65
66 public static final String PLACE_PREFIX = IssueListToolWindowPanel.class.getSimpleName();
67 private ProjectCfgManagerImpl projectCfgManager;
68 private final CfgManager cfgManager;
69 private final PluginConfiguration pluginConfiguration;
70 private JiraWorkspaceConfiguration jiraWorkspaceConfiguration;
71
72 private static final String SERVERS_TOOL_BAR = "ThePlugin.JiraServers.ServersToolBar";
73 private JIRAFilterListModel jiraFilterListModel;
74 private JIRAIssueTreeBuilder issueTreeBuilder;
75 private JIRAIssueListModelBuilder jiraIssueListModelBuilder;
76 private RecentlyOpenIssuesCache recentlyOpenIssuesCache;
77 private JIRAFilterListBuilder jiraFilterListModelBuilder;
78 private JiraIssueGroupBy groupBy;
79 @NotNull
80 private final JiraManualFilterDetailsPanel manualFilterEditDetailsPanel;
81 private JIRAFilterTree jiraFilterTree;
82
83 private JIRAServerFacade jiraServerFacade;
84
85 private JIRAIssueListModel currentIssueListModel;
86
87 private SearchingJIRAIssueListModel searchingIssueListModel;
88
89 private JIRAServerModel jiraServerModel;
90
91 private ConfigurationListener configListener = new LocalConfigurationListener();
92
93 private boolean groupSubtasksUnderParent;
94
95 private static final String THE_PLUGIN_JIRA_ISSUES_ISSUES_TOOL_BAR = "ThePlugin.JiraIssues.IssuesToolBar";
96
97 private JIRAIssueListModel baseIssueListModel;
98
99 private Timer timer;
100
101 private static final int ONE_SECOND = 1000;
102
103 public IssueListToolWindowPanel(@NotNull final Project project,
104 @NotNull final ProjectCfgManagerImpl projectCfgManager,
105 @NotNull final CfgManager cfgManager,
106 @NotNull final PluginConfiguration pluginConfiguration,
107 @NotNull final JiraWorkspaceConfiguration jiraWorkspaceConfiguration,
108 @NotNull final IssueToolWindowFreezeSynchronizator freezeSynchronizator,
109 @NotNull final JIRAIssueListModel issueModel,
110 @NotNull final JIRAIssueListModelBuilder jiraIssueListModelBuilder,
111 @NotNull final RecentlyOpenIssuesCache recentlyOpenIssuesCache,
112 @NotNull final JIRAFilterListBuilder filterListBuilder,
113 @NotNull final JIRAServerModel jiraServerModel) {
114 super(project, SERVERS_TOOL_BAR, THE_PLUGIN_JIRA_ISSUES_ISSUES_TOOL_BAR);
115
116 this.projectCfgManager = projectCfgManager;
117 this.cfgManager = cfgManager;
118 this.pluginConfiguration = pluginConfiguration;
119 this.jiraWorkspaceConfiguration = jiraWorkspaceConfiguration;
120 this.jiraIssueListModelBuilder = jiraIssueListModelBuilder;
121 this.recentlyOpenIssuesCache = recentlyOpenIssuesCache;
122
123 jiraServerFacade = JIRAServerFacadeImpl.getInstance();
124
125 if (jiraWorkspaceConfiguration.getView() != null && jiraWorkspaceConfiguration.getView().getGroupBy() != null) {
126 groupBy = jiraWorkspaceConfiguration.getView().getGroupBy();
127 groupSubtasksUnderParent = jiraWorkspaceConfiguration.getView().isCollapseSubtasksUnderParent();
128 } else {
129 groupBy = JiraIssueGroupBy.TYPE;
130 groupSubtasksUnderParent = false;
131 }
132 jiraFilterListModel = getJIRAFilterListModel();
133 baseIssueListModel = issueModel;
134 JIRAIssueListModel sortingIssueListModel = new SortingByPriorityJIRAIssueListModel(baseIssueListModel);
135 searchingIssueListModel = new SearchingJIRAIssueListModel(sortingIssueListModel);
136 currentIssueListModel = searchingIssueListModel;
137
138 issueTreeBuilder = new JIRAIssueTreeBuilder(getGroupBy(), groupSubtasksUnderParent, currentIssueListModel, project,
139 projectCfgManager);
140
141 this.jiraServerModel = jiraServerModel;
142
143 jiraIssueListModelBuilder.setModel(baseIssueListModel);
144 jiraFilterListModelBuilder = filterListBuilder;
145 if (jiraFilterListModelBuilder != null) {
146 jiraFilterListModelBuilder.setListModel(jiraFilterListModel);
147 jiraFilterListModelBuilder.setProjectId(CfgUtil.getProjectId(project));
148 jiraFilterListModelBuilder.setJiraWorkspaceCfg(jiraWorkspaceConfiguration);
149 }
150 currentIssueListModel.addModelListener(new LocalJiraIssueListModelListener());
151
152 currentIssueListModel.addFrozenModelListener(new FrozenModelListener() {
153 public void modelFrozen(FrozenModel model, boolean frozen) {
154 if (getStatusBarPane() != null) {
155 getStatusBarPane().setEnabled(!frozen);
156 }
157 if (getSearchField() != null) {
158 getSearchField().setEnabled(!frozen);
159 }
160 }
161 });
162
163 manualFilterEditDetailsPanel = new JiraManualFilterDetailsPanel(jiraFilterListModel, this.jiraWorkspaceConfiguration,
164 getProject(), jiraServerModel);
165
166 getStatusBarPane().addMoreIssuesListener(new HyperlinkListener() {
167 public void hyperlinkUpdate(HyperlinkEvent e) {
168 refreshIssues(false);
169 }
170 });
171
172 addIssuesTreeListeners();
173 addSearchBoxListener();
174 freezeSynchronizator.setIssueModel(currentIssueListModel);
175 freezeSynchronizator.setServerModel(jiraServerModel);
176 freezeSynchronizator.setFilterModel(jiraFilterListModel);
177
178 init(0);
179
180
181 jiraFilterTree.addSelectionListener(new LocalJiraFilterTreeSelectionListener());
182
183 jiraFilterListModel.addModelListener(new JIRAFilterListModelListener() {
184 public void manualFilterChanged(final JIRAManualFilter manualFilter, final ServerData jiraServer) {
185
186 refreshIssues(manualFilter, jiraServer, true);
187 }
188
189 public void modelChanged(final JIRAFilterListModel listModel) {
190 }
191
192 public void serverRemoved(final JIRAFilterListModel filterListModel) {
193 }
194
195 public void serverAdded(final JIRAFilterListModel filterListModel) {
196 }
197
198 public void serverNameChanged(final JIRAFilterListModel filterListModel) {
199 }
200 });
201
202 }
203
204 protected void showManualFilterPanel(final JIRAManualFilter manualFilter, final ServerData jiraServerCfg) {
205 getSplitLeftPane().setOrientation(true);
206 manualFilterEditDetailsPanel.setFilter(manualFilter, jiraServerCfg);
207 getSplitLeftPane().setSecondComponent(manualFilterEditDetailsPanel);
208 getSplitLeftPane().setProportion(MANUAL_FILTER_PROPORTION_VISIBLE);
209 }
210
211 protected void hideManualFilterPanel() {
212 getSplitLeftPane().setOrientation(true);
213 getSplitLeftPane().setSecondComponent(null);
214 getSplitLeftPane().setProportion(MANUAL_FILTER_PROPORTION_HIDDEN);
215 }
216
217 public ProjectCfgManagerImpl getProjectCfgManager() {
218 return projectCfgManager;
219 }
220
221 public void init() {
222 ProgressManager.getInstance().run(new Task.Backgroundable(project, "Retrieving recently viewed issues", false) {
223 public void run(@NotNull final ProgressIndicator progressindicator) {
224 recentlyOpenIssuesCache.loadRecenltyOpenIssues();
225 }
226 });
227 }
228
229 @Override
230 protected void addSearchBoxListener() {
231 getSearchField().addDocumentListener(new DocumentListener() {
232 public void insertUpdate(DocumentEvent e) {
233 triggerDelayedSearchBoxUpdate();
234 }
235
236 public void removeUpdate(DocumentEvent e) {
237 triggerDelayedSearchBoxUpdate();
238 }
239
240 public void changedUpdate(DocumentEvent e) {
241 triggerDelayedSearchBoxUpdate();
242 }
243 });
244 getSearchField().addKeyboardListener(new KeyListener() {
245 public void keyTyped(KeyEvent e) {
246 }
247
248 public void keyPressed(KeyEvent e) {
249 if (e.getKeyCode() == KeyEvent.VK_ENTER) {
250 getSearchField().addCurrentTextToHistory();
251 }
252 }
253
254 public void keyReleased(KeyEvent e) {
255 }
256 });
257 }
258
259 private void triggerDelayedSearchBoxUpdate() {
260 if (timer != null && timer.isRunning()) {
261 return;
262 }
263 timer = new Timer(ONE_SECOND, new ActionListener() {
264 public void actionPerformed(ActionEvent e) {
265 searchingIssueListModel.setSearchTerm(getSearchField().getText());
266 }
267 });
268 timer.setRepeats(false);
269 timer.start();
270 }
271
272 public JIRAIssueListModel getBaseIssueListModel() {
273 return baseIssueListModel;
274 }
275
276
277 private void addIssuesTreeListeners() {
278 getRightTree().addKeyListener(new KeyAdapter() {
279 @Override
280 public void keyPressed(KeyEvent e) {
281 JIRAIssue issue = getSelectedIssue();
282 if (e.getKeyCode() == KeyEvent.VK_ENTER && issue != null) {
283 openIssue(issue);
284 }
285 }
286 });
287
288 getRightTree().addMouseListener(new PopupAwareMouseAdapter() {
289
290 @Override
291 public void mouseClicked(final MouseEvent e) {
292 final JIRAIssue issue = getSelectedIssue();
293 if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2 && issue != null) {
294 openIssue(issue);
295 }
296 }
297
298 @Override
299 protected void onPopup(MouseEvent e) {
300 int selRow = getRightTree().getRowForLocation(e.getX(), e.getY());
301 TreePath selPath = getRightTree().getPathForLocation(e.getX(), e.getY());
302 if (selRow != -1 && selPath != null) {
303 getRightTree().setSelectionPath(selPath);
304 if (getSelectedIssue() != null) {
305 launchContextMenu(e);
306 }
307 }
308 }
309 });
310 }
311
312 private void launchContextMenu(MouseEvent e) {
313 final DefaultActionGroup actionGroup = new DefaultActionGroup();
314
315 final ActionGroup configActionGroup = (ActionGroup) ActionManager
316 .getInstance().getAction("ThePlugin.JiraIssues.IssuePopupMenu");
317 actionGroup.addAll(configActionGroup);
318
319 final ActionPopupMenu popup = ActionManager.getInstance().createActionPopupMenu("Context menu", actionGroup);
320 addIssueActionsSubmenu(actionGroup, popup);
321
322 final JPopupMenu jPopupMenu = popup.getComponent();
323 jPopupMenu.show(e.getComponent(), e.getX(), e.getY());
324 }
325
326 private void addIssueActionsSubmenu(DefaultActionGroup actionGroup, final ActionPopupMenu popup) {
327 final DefaultActionGroup submenu = new DefaultActionGroup("Querying for Actions... ", true) {
328 @Override
329 public void update(AnActionEvent event) {
330 super.update(event);
331
332 if (getChildrenCount() > 0) {
333 event.getPresentation().setText("Issue Workflow Actions");
334 }
335 }
336 };
337 actionGroup.add(submenu);
338
339 final JIRAIssue issue = getSelectedIssue();
340 List<JIRAAction> actions = JiraIssueAdapter.get(issue).getCachedActions();
341 if (actions != null) {
342 for (JIRAAction a : actions) {
343 submenu.add(new RunIssueActionAction(this, jiraServerFacade, issue, a, jiraIssueListModelBuilder));
344 }
345 } else {
346 Thread t = new Thread() {
347 @Override
348 public void run() {
349 try {
350 ServerData jiraServer = issue.getServer();
351
352 if (jiraServer != null) {
353 final List<JIRAAction> actions = jiraServerFacade.getAvailableActions(jiraServer, issue);
354
355 JiraIssueAdapter.get(issue).setCachedActions(actions);
356 SwingUtilities.invokeLater(new Runnable() {
357 public void run() {
358 JPopupMenu pMenu = popup.getComponent();
359 if (pMenu.isVisible()) {
360 for (JIRAAction a : actions) {
361 submenu.add(new RunIssueActionAction(IssueListToolWindowPanel.this,
362 jiraServerFacade, issue, a, jiraIssueListModelBuilder));
363 }
364
365
366 pMenu.setVisible(false);
367 pMenu.setVisible(true);
368 }
369 }
370 });
371 }
372 } catch (JIRAException e) {
373 setStatusErrorMessage("Query for issue " + issue.getKey() + " actions failed: " + e.getMessage(), e);
374 } catch (NullPointerException e) {
375
376 }
377 }
378 };
379 t.start();
380 }
381 }
382
383 private JIRAIssue getSelectedIssue() {
384 return getRightTree().getSelectedIssue();
385 }
386
387 public void openIssue(@NotNull JIRAIssue issue) {
388 if (issue.getServer() != null) {
389 recentlyOpenIssuesCache.addIssue(issue);
390
391 IdeaHelper.getIssueDetailsToolWindow(getProject()).showIssue(issue, baseIssueListModel);
392
393 }
394 }
395
396 public void openIssue(@NotNull final String issueKey, @NotNull final ServerData jiraServer) {
397 JIRAIssue issue = null;
398 for (JIRAIssue i : baseIssueListModel.getIssues()) {
399 if (i.getKey().equals(issueKey) && i.getServer().getServerId().equals(jiraServer.getServerId())) {
400 issue = i;
401 break;
402 }
403 }
404
405 if (issue != null) {
406 openIssue(issue);
407 } else {
408 Task.Backgroundable task = new Task.Backgroundable(getProject(), "Fetching JIRA issue " + issueKey, false) {
409 private JIRAIssue issue;
410 private Throwable exception;
411
412 @Override
413 public void run(@NotNull ProgressIndicator progressIndicator) {
414 progressIndicator.setIndeterminate(true);
415 try {
416 if (jiraServer != null) {
417 issue = jiraServerFacade.getIssue(jiraServer, issueKey);
418 jiraIssueListModelBuilder.updateIssue(issue);
419
420 } else {
421 exception = new RuntimeException("No JIRA server defined!");
422 }
423 } catch (JIRAException e) {
424 exception = e;
425 }
426 }
427
428 @Override
429 public void onSuccess() {
430 if (getProject().isDisposed()) {
431 return;
432 }
433 if (exception != null) {
434 final String serverName = jiraServer != null ? jiraServer.getName() : "[UNDEFINED!]";
435 DialogWithDetails.showExceptionDialog(getProject(),
436 "Cannot fetch issue " + issueKey + " from server " + serverName, exception);
437 return;
438 }
439 if (issue != null) {
440 openIssue(issue);
441 }
442 }
443 };
444 task.queue();
445 }
446 }
447
448 public boolean openIssue(@NotNull final String issueKey, @NotNull final String serverUrl) {
449
450 ServerData server = CfgUtil.findServer(
451 serverUrl, cfgManager.getAllServers(CfgUtil.getProjectId(project), ServerType.JIRA_SERVER), projectCfgManager);
452
453 if (server != null) {
454 openIssue(issueKey, server);
455 return true;
456 }
457
458
459 URL url;
460
461 try {
462 url = new URL(serverUrl);
463 } catch (MalformedURLException e) {
464 PluginUtil.getLogger().warn("Error opening issue. Invalid url [" + serverUrl + "]", e);
465 return false;
466 }
467
468 server = CfgUtil.findServer(url, cfgManager.getAllServers(CfgUtil.getProjectId(project), ServerType.JIRA_SERVER),
469 projectCfgManager);
470
471 if (server != null) {
472 openIssue(issueKey, server);
473 return true;
474 }
475
476 return false;
477 }
478
479 public void assignIssueToMyself(@NotNull final JIRAIssue issue) {
480
481 if (issue == null) {
482 return;
483 }
484 try {
485 ServerData jiraServer = getSelectedServer();
486 if (jiraServer != null) {
487 assignIssue(issue, jiraServer.getUserName());
488 }
489 } catch (NullPointerException ex) {
490
491
492 }
493 }
494
495 public void assignIssueToSomebody(@NotNull final JIRAIssue issue) {
496 if (issue == null) {
497 return;
498 }
499 final GetUserNameDialog getUserNameDialog = new GetUserNameDialog(issue.getKey());
500 getUserNameDialog.show();
501 if (getUserNameDialog.isOK()) {
502 try {
503 assignIssue(issue, getUserNameDialog.getName());
504 } catch (NullPointerException ex) {
505
506 }
507 }
508 }
509
510 private void assignIssue(final JIRAIssue issue, final String assignee) {
511
512 Task.Backgroundable assign = new Task.Backgroundable(getProject(), "Assigning Issue", false) {
513
514 @Override
515 public void run(@NotNull final ProgressIndicator indicator) {
516 setStatusInfoMessage("Assigning issue " + issue.getKey() + " to " + assignee + "...");
517 try {
518
519 ServerData jiraServer = getSelectedServer();
520 if (jiraServer != null) {
521 jiraServerFacade.setAssignee(jiraServer, issue, assignee);
522 setStatusInfoMessage("Assigned issue " + issue.getKey() + " to " + assignee);
523 jiraIssueListModelBuilder.reloadIssue(issue.getKey(), jiraServer);
524 }
525 } catch (JIRAException e) {
526 setStatusErrorMessage("Failed to assign issue " + issue.getKey() + ": " + e.getMessage(), e);
527 }
528 }
529 };
530
531 ProgressManager.getInstance().run(assign);
532 }
533
534 public boolean createChangeListAction(@NotNull final JIRAIssue issue) {
535 String changeListName = issue.getKey() + " - " + issue.getSummary();
536 final ChangeListManager changeListManager = ChangeListManager.getInstance(getProject());
537 ChangesetCreate c;
538
539 LocalChangeList changeList = changeListManager.findChangeList(changeListName);
540 if (changeList == null) {
541 c = new ChangesetCreate(issue.getKey());
542 c.setChangesetName(changeListName);
543 c.setChangestComment(changeListName + "\n");
544 c.setActive(true);
545 c.show();
546 if (c.isOK()) {
547 changeListName = c.getChangesetName();
548 changeList = changeListManager.addChangeList(changeListName, c.getChangesetComment());
549 if (c.isActive()) {
550 changeListManager.setDefaultChangeList(changeList);
551 }
552 }
553 } else {
554 changeListManager.setDefaultChangeList(changeList);
555 return true;
556 }
557
558 return c.isOK();
559 }
560
561 public void addCommentToSelectedIssue() {
562
563 final JIRAIssue issue = getSelectedIssue();
564 if (issue != null) {
565 addCommentToIssue(issue.getKey(), issue.getServer());
566 }
567 }
568
569 public void addCommentToIssue(final String issueKey, final ServerData jiraServer) {
570 final IssueCommentDialog issueCommentDialog = new IssueCommentDialog(issueKey);
571 issueCommentDialog.show();
572 if (issueCommentDialog.isOK()) {
573 Task.Backgroundable comment = new Task.Backgroundable(getProject(), "Commenting Issue", false) {
574 @Override
575 public void run(@NotNull final ProgressIndicator indicator) {
576 EventQueue.invokeLater(new Runnable() {
577 public void run() {
578 setStatusInfoMessage("Commenting issue " + issueKey + "...");
579 }
580 });
581 try {
582 if (jiraServer != null) {
583 jiraServerFacade.addComment(jiraServer, issueKey, issueCommentDialog.getComment());
584 EventQueue.invokeLater(new Runnable() {
585 public void run() {
586 setStatusInfoMessage("Commented issue " + issueKey);
587 }
588 });
589 }
590 } catch (final JIRAException e) {
591 EventQueue.invokeLater(new Runnable() {
592 public void run() {
593 setStatusErrorMessage("Issue not commented: " + e.getMessage(), e);
594 }
595 });
596 }
597 }
598 };
599
600 ProgressManager.getInstance().run(comment);
601 }
602 }
603
604 public boolean logWorkOrDeactivateIssue(final JIRAIssue issue, final ServerData jiraServer, String initialLog,
605 final boolean deactivateIssue, DeactivateIssueResultHandler resultHandler) {
606 if (issue != null) {
607 final WorkLogCreateAndMaybeDeactivateDialog dialog =
608 new WorkLogCreateAndMaybeDeactivateDialog(jiraServer, issue, getProject(), initialLog,
609 deactivateIssue, jiraWorkspaceConfiguration);
610 dialog.show();
611 if (dialog.isOK()) {
612 Task.Backgroundable logWork =
613 new LogWorkWorkerTask(issue, dialog, jiraServer, deactivateIssue, resultHandler);
614 ProgressManager.getInstance().run(logWork);
615 }
616 return dialog.isOK();
617 }
618 return false;
619 }
620
621
622
623
624
625
626
627 private JIRAIssue assignIssueAndPutInProgress(@NotNull final JIRAIssue issue) {
628 JIRAIssue updatedIssue = issue;
629 final ServerData server = issue.getServer();
630
631 if (!issue.getAssigneeId().equals(server.getUserName())) {
632 setStatusInfoMessage("Assigning issue " + issue.getKey() + " to me...");
633 try {
634 jiraServerFacade.setAssignee(server, issue, server.getUserName());
635 } catch (JIRAException e) {
636 final String msg = "Error starting progress on issue. Assigning failed: ";
637 setStatusErrorMessage(msg + e.getMessage(), e);
638 PluginUtil.getLogger().warn(msg + e.getMessage(), e);
639 return updatedIssue;
640 }
641 }
642
643 setStatusInfoMessage("Retrieving available actions for issue");
644 List<JIRAAction> actions;
645 try {
646 actions = jiraServerFacade.getAvailableActions(server, issue);
647 } catch (JIRAException e) {
648 final String msg = "Error starting progress on issue. Retrieving actions failed: ";
649 setStatusErrorMessage(msg + e.getMessage(), e);
650 PluginUtil.getLogger().warn(msg + e.getMessage(), e);
651 return updatedIssue;
652 }
653
654 for (JIRAAction a : actions) {
655 if (a.getId() == Constants.JiraActionId.START_PROGRESS.getId()) {
656 setStatusInfoMessage("Starting progress on " + issue.getKey() + "...");
657 try {
658 jiraServerFacade.progressWorkflowAction(server, issue, a);
659 } catch (JIRAException e) {
660 final String msg = "Error starting progress on issue. Perform workflow action failed: ";
661 setStatusErrorMessage(msg + e.getMessage(), e);
662 PluginUtil.getLogger().warn(msg + e.getMessage(), e);
663 return updatedIssue;
664 }
665 JIRAIssueProgressTimestampCache.getInstance().setTimestamp(server, issue);
666 break;
667 }
668 }
669
670 setStatusInfoMessage("Refreshing issue");
671 try {
672 updatedIssue = jiraServerFacade.getIssue(server, issue.getKey());
673 } catch (JIRAException e) {
674 setStatusErrorMessage("Error starting progress on issue: " + e.getMessage(), e);
675 PluginUtil.getLogger().warn("Error refreshing issue: " + e.getMessage(), e);
676 return updatedIssue;
677 }
678
679 if (updatedIssue.getStatusId() != Constants.JiraStatusId.IN_PROGRESS.getId()) {
680 setStatusErrorMessage("Progress on " + issue.getKey() + " not started on JIRA side");
681 } else {
682 setStatusInfoMessage("Progress on " + issue.getKey() + " started");
683 }
684
685 return updatedIssue;
686 }
687
688 public void startWorkingOnIssueAndActivate(@NotNull final JIRAIssue issue, final ActiveJiraIssue newActiveIssue) {
689
690 final boolean isOk = createChangeListAction(issue);
691
692 if (isOk) {
693 ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), "Starting Work on Issue", false) {
694
695 private JIRAIssue updatedIssue = issue;
696
697 @Override
698 public void run(@NotNull final ProgressIndicator indicator) {
699 updatedIssue = assignIssueAndPutInProgress(issue);
700 }
701
702 public void onSuccess() {
703 jiraIssueListModelBuilder.updateIssue(updatedIssue);
704 ActiveIssueUtils.setActiveJiraIssue(project, newActiveIssue, updatedIssue);
705 }
706 });
707 } else {
708 ActiveIssueUtils.setActiveJiraIssue(project, null, issue);
709 }
710
711 pluginConfiguration.getGeneralConfigurationData().bumpCounter("a");
712 }
713
714 private void refreshFilterModel() {
715 try {
716 jiraFilterListModelBuilder.rebuildModel(jiraServerModel);
717 } catch (JIRAFilterListBuilder.JIRAServerFiltersBuilderException e) {
718 Collection<Throwable> exceptions = new ArrayList<Throwable>();
719 for (JIRAException ex : e.getExceptions().values()) {
720 exceptions.add(ex);
721 }
722
723 setStatusErrorMessages("Some Jira servers did not return saved filters", exceptions);
724 }
725 }
726
727
728 public void refreshIssues(final boolean reload) {
729 JIRAManualFilter manualFilter = jiraFilterTree.getSelectedManualFilter();
730 JIRASavedFilter savedFilter = jiraFilterTree.getSelectedSavedFilter();
731 ServerData serverCfg = getSelectedServer();
732 if (savedFilter != null) {
733 refreshIssues(savedFilter, serverCfg, reload);
734 } else if (manualFilter != null) {
735 refreshIssues(manualFilter, serverCfg, reload);
736 } else if (jiraFilterTree.isRecentlyOpenSelected()) {
737 refreshRecenltyOpenIssues(reload);
738 }
739 }
740
741 private void refreshIssues(final JIRAManualFilter manualFilter, final ServerData jiraServerCfg, final boolean reload) {
742 if (WindowManager.getInstance().getIdeFrame(getProject()) == null) {
743 return;
744 }
745 Task.Backgroundable task = new Task.Backgroundable(getProject(), "Retrieving issues", false) {
746 @Override
747 public void run(@NotNull final ProgressIndicator indicator) {
748 try {
749 getStatusBarPane().setInfoMessage("Loading issues...", false);
750 jiraIssueListModelBuilder.addIssuesToModel(manualFilter, jiraServerCfg,
751 pluginConfiguration.getJIRAConfigurationData().getPageSize(), reload);
752 } catch (JIRAException e) {
753 setStatusErrorMessage(e.getMessage(), e);
754 }
755 }
756 };
757 ProgressManager.getInstance().run(task);
758 }
759
760 private void refreshIssues(final JIRASavedFilter savedFilter, final ServerData jiraServerCfg, final boolean reload) {
761 if (WindowManager.getInstance().getIdeFrame(getProject()) == null) {
762 return;
763 }
764 Task.Backgroundable task = new Task.Backgroundable(getProject(), "Retrieving issues", false) {
765 @Override
766 public void run(@NotNull final ProgressIndicator indicator) {
767 try {
768 getStatusBarPane().setInfoMessage("Loading issues...", false);
769 jiraIssueListModelBuilder.addIssuesToModel(savedFilter, jiraServerCfg,
770 pluginConfiguration.getJIRAConfigurationData().getPageSize(), reload);
771 } catch (JIRAException e) {
772 setStatusErrorMessage(e.getMessage(), e);
773 }
774 }
775 };
776 ProgressManager.getInstance().run(task);
777 }
778
779
780 private void refreshRecenltyOpenIssues(final boolean reload) {
781 if (WindowManager.getInstance().getIdeFrame(getProject()) == null) {
782 return;
783 }
784 Task.Backgroundable task = new Task.Backgroundable(getProject(), "Retrieving issues", false) {
785 @Override
786 public void run(@NotNull final ProgressIndicator indicator) {
787 try {
788 getStatusBarPane().setInfoMessage("Loading issues...", false);
789 jiraIssueListModelBuilder.addRecenltyOpenIssuesToModel(reload);
790 } catch (JIRAException e) {
791 setStatusErrorMessage(e.getMessage(), e);
792 }
793 }
794 };
795 ProgressManager.getInstance().run(task);
796 }
797
798 @SuppressWarnings({"UnusedDeclaration"})
799 public void configurationUpdated(final ProjectConfiguration aProjectConfiguration) {
800 refreshModels();
801 }
802
803
804
805
806 public void refreshModels() {
807 Task.Backgroundable task = new MetadataFetcherBackgroundableTask();
808 ProgressManager.getInstance().run(task);
809 }
810
811
812 public void projectRegistered() {
813
814 }
815
816 public JiraIssueGroupBy getGroupBy() {
817 return groupBy;
818 }
819
820 public void setGroupBy(JiraIssueGroupBy groupBy) {
821 this.groupBy = groupBy;
822 issueTreeBuilder.setGroupBy(groupBy);
823 issueTreeBuilder.rebuild(getRightTree(), getRightPanel());
824
825
826
827 jiraWorkspaceConfiguration.getView().setGroupBy(groupBy);
828 }
829
830 public void createIssue() {
831
832 if (jiraIssueListModelBuilder == null) {
833 return;
834 }
835
836 final ServerData server = getSelectedServer();
837
838 if (server != null) {
839 final IssueCreateDialog issueCreateDialog =
840 new IssueCreateDialog(this, project, jiraServerModel, server, jiraWorkspaceConfiguration);
841
842 issueCreateDialog.initData();
843 issueCreateDialog.show();
844 }
845 }
846
847 public ConfigurationListener getConfigListener() {
848 return configListener;
849 }
850
851 public boolean isGroupSubtasksUnderParent() {
852 return groupSubtasksUnderParent;
853 }
854
855 public void setGroupSubtasksUnderParent(boolean state) {
856 if (state != groupSubtasksUnderParent) {
857 groupSubtasksUnderParent = state;
858 issueTreeBuilder.setGroupSubtasksUnderParent(groupSubtasksUnderParent);
859 issueTreeBuilder.rebuild(getRightTree(), getRightScrollPane());
860
861 jiraWorkspaceConfiguration.getView().setCollapseSubtasksUnderParent(groupSubtasksUnderParent);
862 }
863 }
864
865 public JIRAFilterListModel getJIRAFilterListModel() {
866 if (jiraFilterListModel == null) {
867 jiraFilterListModel = new JIRAFilterListModel();
868 }
869 return jiraFilterListModel;
870 }
871
872 public ServerData getSelectedServer() {
873 ServerData server = jiraFilterTree != null ? jiraFilterTree.getSelectedServer() : null;
874 if (server != null) {
875 return server;
876 }
877
878 if (projectCfgManager.getDefaultJiraServer() != null) {
879 return projectCfgManager.getDefaultJiraServer();
880 }
881
882 if (getSelectedIssue() != null) {
883 return getSelectedIssue().getServer();
884 }
885
886 return null;
887 }
888
889 public boolean isRecentlyOpenFilterSelected() {
890 return jiraFilterTree != null && jiraFilterTree.isRecentlyOpenSelected();
891 }
892
893
894
895
896 public List<JIRAIssue> getLoadedRecenltyOpenIssues() {
897 return new ArrayList<JIRAIssue>(recentlyOpenIssuesCache.getLoadedRecenltyOpenIssues());
898 }
899
900
901
902
903
904
905 private class MetadataFetcherBackgroundableTask extends Task.Backgroundable {
906 private Collection<ServerData> servers = null;
907 private boolean refreshIssueList = false;
908
909
910
911
912 public MetadataFetcherBackgroundableTask() {
913 super(IssueListToolWindowPanel.this.getProject(), "Retrieving JIRA information", false);
914 fillServerData();
915 jiraServerModel.clearAll();
916 refreshIssueList = true;
917 }
918
919 private void fillServerData() {
920 servers = new ArrayList<ServerData>();
921 for (JiraServerCfg serverCfg : cfgManager.getAllEnabledJiraServers(CfgUtil.getProjectId(getProject()))) {
922 servers.add(projectCfgManager.getServerData(serverCfg));
923 }
924 }
925
926
927
928
929
930
931
932 public MetadataFetcherBackgroundableTask(final JiraServerCfg server, boolean refreshIssueList) {
933 super(IssueListToolWindowPanel.this.getProject(), "Retrieving JIRA information", false);
934 this.servers = Arrays.asList(projectCfgManager.getServerData(server));
935 this.refreshIssueList = refreshIssueList;
936 }
937
938 @Override
939 public void run(@NotNull final ProgressIndicator indicator) {
940
941 try {
942 jiraServerModel.setModelFrozen(true);
943
944 for (ServerData server : servers) {
945 try {
946
947 Boolean serverCheck = jiraServerModel.checkServer(server);
948 if (serverCheck == null || !serverCheck) {
949 setStatusErrorMessage("Unable to connect to server. " + jiraServerModel.getErrorMessage(server));
950 MissingPasswordHandlerQueue.addHandler(new MissingPasswordHandlerJIRA(jiraServerFacade,
951 (JiraServerCfg) cfgManager.getServer(CfgUtil.getProjectId(project), server), project));
952 continue;
953 }
954
955 final String serverStr = "[" + server.getName() + "] ";
956 setStatusInfoMessage(serverStr + "Retrieving saved filters...");
957 jiraServerModel.getSavedFilters(server);
958 setStatusInfoMessage(serverStr + "Retrieving projects...");
959 jiraServerModel.getProjects(server);
960 setStatusInfoMessage(serverStr + "Retrieving issue types...");
961 jiraServerModel.getIssueTypes(server, null, true);
962 setStatusInfoMessage(serverStr + "Retrieving statuses...");
963 jiraServerModel.getStatuses(server);
964 setStatusInfoMessage(serverStr + "Retrieving resolutions...");
965 jiraServerModel.getResolutions(server, true);
966 setStatusInfoMessage(serverStr + "Retrieving priorities...");
967 jiraServerModel.getPriorities(server, true);
968 setStatusInfoMessage(serverStr + "Retrieving projects...");
969 jiraServerModel.getProjects(server);
970 setStatusInfoMessage(serverStr + "Server data query finished");
971 } catch (RemoteApiException e) {
972 setStatusErrorMessage("Unable to connect to server. " + jiraServerModel.getErrorMessage(server), e);
973 } catch (JIRAException e) {
974 setStatusErrorMessage("Cannot download details:" + e.getMessage(), e);
975 }
976 }
977 } finally {
978
979 jiraServerModel.setModelFrozen(false);
980 }
981 }
982
983 @Override
984 public void onSuccess() {
985 refreshFilterModel();
986 if (refreshIssueList) {
987 jiraFilterListModel.fireModelChanged();
988 } else {
989 jiraFilterListModel.fireServerAdded();
990 }
991 }
992 }
993
994 @Nullable
995 public Object getData(@NotNull final String dataId) {
996 if (dataId.equals(Constants.ISSUE)) {
997 return getSelectedIssue();
998 }
999 if (dataId.equals(Constants.SERVER)) {
1000 return getSelectedServer();
1001 }
1002 return null;
1003 }
1004
1005 private class LocalConfigurationListener extends ConfigurationListenerAdapter {
1006
1007 @Override
1008 public void serverConnectionDataChanged(final ServerId serverId) {
1009 ServerCfg server = cfgManager.getServer(CfgUtil.getProjectId(project), serverId);
1010 if (server instanceof JiraServerCfg && server.getServerType() == ServerType.JIRA_SERVER) {
1011 jiraServerModel.clear(server.getServerId());
1012 Task.Backgroundable task = new MetadataFetcherBackgroundableTask((JiraServerCfg) server, true);
1013 ProgressManager.getInstance().run(task);
1014 }
1015 }
1016
1017 @Override
1018 public void serverNameChanged(final ServerId serverId) {
1019 ServerCfg server = cfgManager.getServer(CfgUtil.getProjectId(project), serverId);
1020 if (server instanceof JiraServerCfg) {
1021 jiraServerModel.replace(projectCfgManager.getServerData(server));
1022 refreshFilterModel();
1023 jiraFilterListModel.fireServerNameChanged();
1024 }
1025 }
1026
1027 @Override
1028 public void serverDisabled(final ServerId serverId) {
1029 ServerCfg server = cfgManager.getServer(CfgUtil.getProjectId(project), serverId);
1030 if (server instanceof JiraServerCfg && server.getServerType() == ServerType.JIRA_SERVER) {
1031 removeServer(serverId, recenltyViewedAffected(server));
1032 }
1033 }
1034
1035 @Override
1036 public void serverRemoved(final ServerCfg oldServer) {
1037 if (oldServer instanceof JiraServerCfg && oldServer.getServerType() == ServerType.JIRA_SERVER) {
1038 removeServer(oldServer.getServerId(), recenltyViewedAffected(oldServer));
1039 }
1040 }
1041
1042 @Override
1043 public void serverEnabled(final ServerId serverId) {
1044 ServerCfg server = cfgManager.getServer(CfgUtil.getProjectId(project), serverId);
1045 addServer(server, recenltyViewedAffected(server));
1046 }
1047
1048 @Override
1049 public void serverAdded(final ServerCfg newServer) {
1050 addServer(newServer, false);
1051 }
1052
1053 private void addServer(final ServerCfg server, boolean refreshIssueList) {
1054 if (server instanceof JiraServerCfg && server.getServerType() == ServerType.JIRA_SERVER) {
1055 Task.Backgroundable task = new MetadataFetcherBackgroundableTask((JiraServerCfg) server, refreshIssueList);
1056 ProgressManager.getInstance().run(task);
1057
1058 }
1059 }
1060
1061 private void removeServer(final ServerId serverId, final boolean reloadIssueList) {
1062 jiraServerModel.clear(serverId);
1063 refreshFilterModel();
1064 jiraFilterListModel.fireServerRemoved();
1065
1066 if (reloadIssueList) {
1067 refreshRecenltyOpenIssues(true);
1068 }
1069 }
1070
1071 private boolean recenltyViewedAffected(final ServerCfg server) {
1072 if (server instanceof JiraServerCfg && server.getServerType() == ServerType.JIRA_SERVER
1073 && jiraFilterTree.isRecentlyOpenSelected()) {
1074
1075 JiraWorkspaceConfiguration conf = IdeaHelper.getProjectComponent(project, JiraWorkspaceConfiguration.class);
1076 if (conf != null) {
1077 final Collection<IssueRecentlyOpenBean> recentlyOpen = conf.getRecentlyOpenIssues();
1078 if (recentlyOpen != null) {
1079 for (IssueRecentlyOpenBean i : recentlyOpen) {
1080 if (i.getServerId().equals(server.getServerId().toString())) {
1081 return true;
1082 }
1083 }
1084 }
1085 }
1086 }
1087 return false;
1088 }
1089
1090 }
1091
1092 @Override
1093 public JTree createRightTree() {
1094 JiraIssueListTree issueTree = new JiraIssueListTree();
1095
1096 new TreeSpeedSearch(issueTree) {
1097 @Override
1098 protected boolean isMatchingElement(Object o, String s) {
1099 TreePath tp = (TreePath) o;
1100 Object node = tp.getLastPathComponent();
1101 if (node instanceof JIRAIssueTreeNode) {
1102 JIRAIssueTreeNode jitn = (JIRAIssueTreeNode) node;
1103 JIRAIssue issue = jitn.getIssue();
1104 return issue.getKey().toLowerCase().contains(s.toLowerCase())
1105 || issue.getSummary().toLowerCase().contains(s.toLowerCase());
1106 } else {
1107 return super.isMatchingElement(o, s);
1108 }
1109 }
1110 };
1111
1112 issueTreeBuilder.rebuild(issueTree, getRightPanel());
1113 return issueTree;
1114 }
1115
1116 @Override
1117 public JiraIssueListTree getRightTree() {
1118 return (JiraIssueListTree) super.getRightTree();
1119 }
1120
1121 @Override
1122 public JTree createLeftTree() {
1123 if (jiraFilterTree == null) {
1124 jiraFilterTree = new JIRAFilterTree(jiraWorkspaceConfiguration, getJIRAFilterListModel());
1125 }
1126
1127 return jiraFilterTree;
1128 }
1129
1130 @Override
1131 public String getActionPlaceName() {
1132 return PLACE_PREFIX + this.getProject().getName();
1133 }
1134
1135 private class LocalJiraFilterTreeSelectionListener implements JiraFilterTreeSelectionListener {
1136
1137 public void selectedSavedFilterNode(final JIRASavedFilter savedFilter, final ServerData jiraServerCfg) {
1138 hideManualFilterPanel();
1139 refreshIssues(savedFilter, jiraServerCfg, true);
1140 jiraWorkspaceConfiguration.getView().setViewServerId(jiraServerCfg.getServerId());
1141 jiraWorkspaceConfiguration.getView().setViewFilterId(Long.toString(savedFilter.getId()));
1142 }
1143
1144 public void selectedManualFilterNode(final JIRAManualFilter manualFilter, final ServerData jiraServerCfg) {
1145 showManualFilterPanel(manualFilter, jiraServerCfg);
1146 jiraWorkspaceConfiguration.getView().setViewServerId(jiraServerCfg.getServerId());
1147 jiraWorkspaceConfiguration.getView().setViewFilterId(JiraFilterConfigurationBean.MANUAL_FILTER);
1148
1149 refreshIssues(manualFilter, jiraServerCfg, true);
1150 }
1151
1152 public void selectionCleared() {
1153 hideManualFilterPanel();
1154
1155 enableGetMoreIssues(false);
1156
1157 jiraWorkspaceConfiguration.getView().setViewServerId("");
1158 jiraWorkspaceConfiguration.getView().setViewFilterId("");
1159
1160 jiraIssueListModelBuilder.reset();
1161 }
1162
1163 public void selectedRecentlyOpenNode() {
1164 hideManualFilterPanel();
1165
1166
1167 refreshRecenltyOpenIssues(true);
1168
1169 jiraWorkspaceConfiguration.getView().setViewServerId("");
1170 jiraWorkspaceConfiguration.getView().setViewFilterId(JiraFilterConfigurationBean.RECENTLY_OPEN_FILTER);
1171 }
1172 }
1173
1174 private class LogWorkWorkerTask extends Task.Backgroundable {
1175 private final JIRAIssue issue;
1176 private final WorkLogCreateAndMaybeDeactivateDialog dialog;
1177 private final ServerData jiraServer;
1178 private final boolean deactivateIssue;
1179 private DeactivateIssueResultHandler resultHandler;
1180 private boolean commitSuccess;
1181
1182 public LogWorkWorkerTask(JIRAIssue issue, WorkLogCreateAndMaybeDeactivateDialog dialog,
1183 ServerData jiraServer, boolean deactivateIssue,
1184 DeactivateIssueResultHandler resultHandler) {
1185
1186 super(IssueListToolWindowPanel.this.getProject(),
1187 deactivateIssue ? "Stopping Work" : "Logging Work", false);
1188
1189 this.issue = issue;
1190 this.dialog = dialog;
1191 this.jiraServer = jiraServer;
1192 this.deactivateIssue = deactivateIssue;
1193 this.resultHandler = resultHandler;
1194 }
1195
1196 @Override
1197 public void run(@NotNull final ProgressIndicator indicator) {
1198 try {
1199 if (jiraServer != null) {
1200 if (!deactivateIssue) {
1201 logWork();
1202 } else {
1203
1204
1205 commitChanges();
1206
1207 if (commitSuccess) {
1208 try {
1209
1210 logWork();
1211
1212
1213
1214
1215
1216
1217 if (!runWorkflowAction(new DeactivateIssueResultHandler() {
1218 public void success() {
1219 if (resultHandler != null) {
1220 resultHandler.success();
1221 }
1222 }
1223
1224 public void failure(Throwable problem) {
1225 if (resultHandler != null) {
1226 resultHandler.failure(problem);
1227 }
1228 }
1229 })) {
1230
1231 if (resultHandler != null) {
1232 resultHandler.success();
1233 }
1234 }
1235
1236
1237 setStatusInfoMessage("Deactivated issue " + issue.getKey());
1238 jiraIssueListModelBuilder.reloadIssue(issue.getKey(), jiraServer);
1239 } catch (JIRAException e) {
1240 if (resultHandler != null) {
1241 resultHandler.failure(e);
1242 }
1243 throw e;
1244 }
1245 } else if (resultHandler != null) {
1246 resultHandler.failure(new JIRAException("Failed to commit changes"));
1247 }
1248 }
1249 }
1250 } catch (JIRAException e) {
1251 if (deactivateIssue) {
1252 setStatusErrorMessage("Issue not deactivated: " + e.getMessage(), e);
1253 } else {
1254 setStatusErrorMessage("Work not logged: " + e.getMessage(), e);
1255 }
1256 }
1257 }
1258
1259 private void commitChanges() {
1260 if (dialog.isCommitChanges()) {
1261 final ChangeListManager changeListManager = ChangeListManager.getInstance(project);
1262 final LocalChangeList list = dialog.getCurrentChangeList();
1263 list.setComment(dialog.getComment());
1264
1265 ApplicationManager.getApplication().invokeAndWait(new Runnable() {
1266 public void run() {
1267 setStatusInfoMessage("Committing changes...");
1268 FileDocumentManager.getInstance().saveAllDocuments();
1269 List<Change> selectedChanges = dialog.getSelectedChanges();
1270 commitSuccess = changeListManager.commitChangesSynchronouslyWithResult(
1271 list, selectedChanges);
1272 }
1273 }, ModalityState.defaultModalityState());
1274
1275 if (commitSuccess) {
1276 WorkLogCreateAndMaybeDeactivateDialog.AfterCommit afterCommit =
1277 dialog.getAfterCommitChangeSetAction();
1278
1279 switch (afterCommit) {
1280 case DEACTIVATE_CHANGESET:
1281
1282 activateDefaultChangeList(changeListManager);
1283 break;
1284 case REMOVE_CHANGESET:
1285 activateDefaultChangeList(changeListManager);
1286 if (!"Default".equals(dialog.getCurrentChangeList().getName())) {
1287 changeListManager.removeChangeList(dialog.getCurrentChangeList());
1288 }
1289 break;
1290 default:
1291 break;
1292 }
1293 setStatusInfoMessage("Deactivated issue " + issue.getKey());
1294 } else {
1295 setStatusErrorMessage(
1296 "Failed to commit change list while deactivating issue " + issue.getKey());
1297 }
1298 } else {
1299
1300 commitSuccess = true;
1301 }
1302 }
1303
1304 private boolean runWorkflowAction(final DeactivateIssueResultHandler handler) {
1305 JIRAAction selectedAction = dialog.getSelectedAction();
1306 if (selectedAction != null) {
1307 setStatusInfoMessage("Running action [" + selectedAction.getName()
1308 + "] on issue " + issue.getKey());
1309 final RunIssueActionAction riaa = new RunIssueActionAction(IssueListToolWindowPanel.this,
1310 jiraServerFacade, issue, selectedAction, jiraIssueListModelBuilder);
1311 SwingUtilities.invokeLater(new Runnable() {
1312 public void run() {
1313 riaa.runIssueAction(project, handler);
1314 }
1315 });
1316 return true;
1317 }
1318 return false;
1319 }
1320
1321 private void logWork() throws JIRAException {
1322 if (dialog.isLogTime()) {
1323 setStatusInfoMessage("Logging work for issue " + issue.getKey() + "...");
1324 Calendar cal = Calendar.getInstance();
1325 cal.setTime(dialog.getStartDate());
1326
1327 String newRemainingEstimate = dialog.getRemainingEstimateUpdateMode()
1328 .equals(RemainingEstimateUpdateMode.MANUAL)
1329 ? dialog.getRemainingEstimateString() : null;
1330 jiraServerFacade.logWork(jiraServer, issue, dialog.getTimeSpentString(),
1331 cal, null,
1332 !dialog.getRemainingEstimateUpdateMode()
1333 .equals(RemainingEstimateUpdateMode.UNCHANGED),
1334 newRemainingEstimate);
1335 JIRAIssueProgressTimestampCache.getInstance().setTimestamp(
1336 jiraServer, issue);
1337 setStatusInfoMessage("Logged work for issue " + issue.getKey());
1338 }
1339 }
1340
1341 private void activateDefaultChangeList(ChangeListManager changeListManager) {
1342 List<LocalChangeList> chLists = changeListManager.getChangeLists();
1343 for (LocalChangeList chl : chLists) {
1344 if ("Default".equals(chl.getName())) {
1345 changeListManager.setDefaultChangeList(chl);
1346 break;
1347 }
1348 }
1349 }
1350 }
1351
1352 private class LocalJiraIssueListModelListener implements JIRAIssueListModelListener {
1353 private boolean singleIssueChanged = false;
1354
1355 public void issueUpdated(final JIRAIssue issue) {
1356 EventQueue.invokeLater(new Runnable() {
1357 public void run() {
1358 singleIssueChanged = true;
1359 JiraIssueAdapter.clearCache(issue);
1360 ActiveIssueUtils.checkIssueState(project, issue);
1361 }
1362 });
1363
1364 }
1365
1366 public void modelChanged(JIRAIssueListModel model) {
1367 SwingUtilities.invokeLater(new ModelChangedRunnable());
1368
1369 SwingUtilities.invokeLater(new Runnable() {
1370 public void run() {
1371 if (!singleIssueChanged) {
1372 jiraIssueListModelBuilder.checkActiveIssue(currentIssueListModel.getIssues());
1373 }
1374 singleIssueChanged = false;
1375 }
1376 });
1377 }
1378
1379 public void issuesLoaded(JIRAIssueListModel model, int loadedIssues) {
1380 if (loadedIssues >= pluginConfiguration.getJIRAConfigurationData().getPageSize()) {
1381 enableGetMoreIssues(true);
1382 setStatusInfoMessage("Loaded " + loadedIssues + " issues", true);
1383 } else {
1384 enableGetMoreIssues(false);
1385 setStatusInfoMessage("Loaded " + loadedIssues + " issues");
1386 }
1387 }
1388
1389 private class ModelChangedRunnable implements Runnable {
1390 public void run() {
1391
1392
1393 if (jiraServerModel == null || projectCfgManager == null) {
1394 return;
1395 }
1396
1397 JiraIssueAdapter.clearCache();
1398 ServerData srvcfg = getSelectedServer();
1399 if (srvcfg == null && !isRecentlyOpenFilterSelected()) {
1400 setStatusInfoMessage("Nothing selected");
1401 issueTreeBuilder.rebuild(getRightTree(), getRightScrollPane());
1402 } else if (srvcfg == null && isRecentlyOpenFilterSelected()) {
1403 Map<Pair<String, ServerId>, String> projects = new HashMap<Pair<String, ServerId>, String>();
1404 for (JiraServerCfg server : projectCfgManager.getCfgManager()
1405 .getAllEnabledJiraServers(CfgUtil.getProjectId(project))) {
1406 try {
1407 for (JIRAProject p : jiraServerModel.getProjects(projectCfgManager.getServerData(server))) {
1408 projects.put(new Pair<String, ServerId>(p.getKey(), server.getServerId()), p.getName());
1409 }
1410 } catch (JIRAException e) {
1411 setStatusErrorMessage("Cannot retrieve projects from server [" + server.getName() + "]. "
1412 + e.getMessage(), e);
1413 }
1414 }
1415 issueTreeBuilder.setProjectKeysToNames(projects);
1416 issueTreeBuilder.rebuild(getRightTree(), getRightScrollPane());
1417 } else if (srvcfg != null) {
1418 Map<Pair<String, ServerId>, String> projectMap = new HashMap<Pair<String, ServerId>, String>();
1419 try {
1420 for (JIRAProject p : jiraServerModel.getProjects(srvcfg)) {
1421 projectMap.put(new Pair<String, ServerId>(p.getKey(), new ServerId(srvcfg.getServerId())),
1422 p.getName());
1423 }
1424 } catch (JIRAException e) {
1425 setStatusErrorMessage("Cannot retrieve projects from server [" + srvcfg.getName() + "]. "
1426 + e.getMessage(), e);
1427 }
1428 issueTreeBuilder.setProjectKeysToNames(projectMap);
1429 issueTreeBuilder.rebuild(getRightTree(), getRightScrollPane());
1430
1431 }
1432 }
1433 }
1434 }
1435 }