View Javadoc

1   /**
2    * Copyright (C) 2008 Atlassian
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.atlassian.theplugin.idea;
18  
19  import com.atlassian.theplugin.cfg.CfgUtil;
20  import com.atlassian.theplugin.commons.UIActionScheduler;
21  import com.atlassian.theplugin.commons.bamboo.BambooPopupInfo;
22  import com.atlassian.theplugin.commons.bamboo.BambooServerFacadeImpl;
23  import com.atlassian.theplugin.commons.bamboo.BambooStatusChecker;
24  import com.atlassian.theplugin.commons.bamboo.BambooStatusDisplay;
25  import com.atlassian.theplugin.commons.bamboo.BambooStatusTooltipListener;
26  import com.atlassian.theplugin.commons.bamboo.BuildStatus;
27  import com.atlassian.theplugin.commons.bamboo.StausIconBambooListener;
28  import com.atlassian.theplugin.commons.cfg.CfgManager;
29  import com.atlassian.theplugin.commons.cfg.ConfigurationListener;
30  import com.atlassian.theplugin.commons.cfg.ProjectConfiguration;
31  import com.atlassian.theplugin.commons.configuration.CrucibleTooltipOption;
32  import com.atlassian.theplugin.commons.configuration.PluginConfiguration;
33  import com.atlassian.theplugin.commons.crucible.CrucibleServerFacade;
34  import com.atlassian.theplugin.commons.crucible.CrucibleServerFacadeImpl;
35  import com.atlassian.theplugin.commons.util.LoggerImpl;
36  import com.atlassian.theplugin.configuration.ProjectConfigurationBean;
37  import com.atlassian.theplugin.idea.autoupdate.ConfirmPluginUpdateHandler;
38  import com.atlassian.theplugin.idea.autoupdate.PluginUpdateIcon;
39  import com.atlassian.theplugin.idea.bamboo.BambooStatusIcon;
40  import com.atlassian.theplugin.idea.bamboo.BambooTableToolWindowPanel;
41  import com.atlassian.theplugin.idea.bamboo.BuildStatusChangedToolTip;
42  import com.atlassian.theplugin.idea.crucible.CruciblePatchSubmitExecutor;
43  import com.atlassian.theplugin.idea.crucible.CrucibleStatusChecker;
44  import com.atlassian.theplugin.idea.crucible.CrucibleStatusIcon;
45  import com.atlassian.theplugin.idea.crucible.CrucibleTableToolWindowPanel;
46  import com.atlassian.theplugin.idea.crucible.comments.ReviewActionEventBroker;
47  import com.atlassian.theplugin.idea.jira.JIRAToolWindowPanel;
48  import com.atlassian.theplugin.jira.JIRAServer;
49  import com.atlassian.theplugin.notification.crucible.CrucibleNotificationTooltip;
50  import com.atlassian.theplugin.notification.crucible.CrucibleReviewNotifier;
51  import com.atlassian.theplugin.remoteapi.MissingPasswordHandler;
52  import com.atlassian.theplugin.util.PluginUtil;
53  import com.intellij.openapi.components.PersistentStateComponent;
54  import com.intellij.openapi.components.ProjectComponent;
55  import com.intellij.openapi.components.State;
56  import com.intellij.openapi.components.Storage;
57  import com.intellij.openapi.project.Project;
58  import com.intellij.openapi.startup.StartupManager;
59  import com.intellij.openapi.ui.DialogWrapper;
60  import com.intellij.openapi.ui.Messages;
61  import com.intellij.openapi.util.IconLoader;
62  import com.intellij.openapi.util.Key;
63  import com.intellij.openapi.vcs.changes.ChangeListManager;
64  import com.intellij.openapi.wm.ToolWindowManager;
65  import com.intellij.peer.PeerFactory;
66  import com.intellij.ui.content.Content;
67  import com.intellij.ui.table.TableView;
68  import org.jetbrains.annotations.NotNull;
69  
70  import javax.swing.*;
71  
72  /**
73   * Per-project plugin component.
74   */
75  @State(name = "atlassian-ide-plugin-workspace",
76  		storages = {@Storage(id = "atlassian-ide-plugin-workspace-id", file = "$WORKSPACE_FILE$") })
77  public class ThePluginProjectComponent implements ProjectComponent, PersistentStateComponent<ProjectConfigurationBean> {
78      private static final String THE_PLUGIN_TOOL_WINDOW_ICON = "/icons/ico_plugin_16.png";
79  
80      private final ProjectConfigurationBean projectConfigurationBean;
81  
82      private final Project project;
83  	private final CfgManager cfgManager;
84  	private final UIActionScheduler actionScheduler;
85  	private BambooStatusIcon statusBarBambooIcon;
86  
87      private CrucibleStatusIcon statusBarCrucibleIcon;
88      private PluginUpdateIcon statusPluginUpdateIcon;
89      private BambooStatusChecker bambooStatusChecker;
90  	private CrucibleStatusChecker crucibleStatusChecker;
91  
92  	private BambooStatusTooltipListener tooltipBambooStatusListener;
93  	private final BambooTableToolWindowPanel bambooToolWindowPanel;
94      private CrucibleTableToolWindowPanel crucibleToolWindowPanel;
95  
96      private final CrucibleServerFacade crucibleServerFacade;
97  
98      private final ToolWindowManager toolWindowManager;
99      private boolean created;
100     private CrucibleReviewNotifier crucibleReviewNotifier;
101 
102 	private final PluginConfiguration pluginConfiguration;
103 
104     private JIRAToolWindowPanel jiraToolWindowPanel;
105     private JIRAServer currentJiraServer;
106 
107 	private PluginToolWindow toolWindow;
108 
109 	public static final Key<ReviewActionEventBroker> BROKER_KEY = Key.create("thePlugin.broker");
110 	private ConfigurationListenerImpl configurationListener;
111 
112 	public ThePluginProjectComponent(Project project, ToolWindowManager toolWindowManager,
113 			PluginConfiguration pluginConfiguration, UIActionScheduler actionScheduler,
114 			ProjectConfigurationBean projectConfigurationBean, CfgManager cfgManager,
115 			BambooTableToolWindowPanel bambooTableToolWindowPanel) {
116 		this.project = project;
117 		this.cfgManager = cfgManager;
118 		project.putUserData(BROKER_KEY, new ReviewActionEventBroker(project));
119 
120 		this.actionScheduler = actionScheduler;
121 		this.toolWindowManager = toolWindowManager;
122 		this.pluginConfiguration = pluginConfiguration;
123 		this.projectConfigurationBean = projectConfigurationBean;
124 		this.crucibleServerFacade = CrucibleServerFacadeImpl.getInstance();
125 		this.bambooToolWindowPanel = bambooTableToolWindowPanel;
126 		/*
127 
128 
129 										WARNING!!!
130 
131 
132 		BEFORE ADDING SOME INITIALIZATION CODE TO COSTRUCTOR THINK TWICE
133 
134 		...MAYBE YOU SHOULD PUT IT INTO THE initializePlugin METHOD
135 		(WHICH IS INVOKED WHEN THE ENTIRE PLUGIN ENVIRONMENT IS SET UP)?
136 
137 
138 		 */
139 		// make findBugs happy
140         statusBarBambooIcon = null;
141         statusBarCrucibleIcon = null;
142         statusPluginUpdateIcon = null;
143         created = false;
144         StartupManager.getInstance(project).registerPostStartupActivity(new Runnable() {
145             public void run() {
146 				LoggerImpl.getInstance().info("Start: Project initializing");
147                 initializePlugin();
148                 LoggerImpl.getInstance().info("End: Project initialized");
149             }
150         });
151 	}
152 
153     public void initComponent() {
154         LoggerImpl.getInstance().info("Init ThePlugin project component.");
155         ChangeListManager.getInstance(project).registerCommitExecutor(
156                 new CruciblePatchSubmitExecutor(project, crucibleServerFacade));
157 
158     }
159 
160     public void disposeComponent() {
161         LoggerImpl.getInstance().info("Dispose ThePlugin project component");
162     }
163 
164     @NotNull
165 	public String getComponentName() {
166         return "ThePluginProjectComponent";
167     }
168 
169 	private void initializePlugin() {
170         // unregister changelistmanager?
171         // only open tool windows for each application that's registered
172         // show something nice if there are non
173         // swap listener for dataretrievedlistener and datachangelisteners
174         // store bamboo between runs in UDC
175         // clean up object model confusion
176 
177         if (!created) {
178 
179 			// wseliga: I don't know yet what do to with comment below
180 			// todo remove that get instance as it can return null. it is better to get it from app component.
181 			this.bambooStatusChecker = new BambooStatusChecker(CfgUtil.getProjectId(project), actionScheduler,
182 					cfgManager,
183 					new MissingPasswordHandler(BambooServerFacadeImpl.getInstance(PluginUtil.getLogger()), cfgManager, project),
184 					PluginUtil.getLogger());
185 
186 			this.crucibleStatusChecker = new CrucibleStatusChecker(cfgManager, project,
187 					pluginConfiguration.getCrucibleConfigurationData(), projectConfigurationBean.getCrucibleConfiguration(),
188 					new MissingPasswordHandler(crucibleServerFacade, cfgManager, project));
189 
190 			// DependencyValidationManager.getHolder(project, "", )
191 			//this.bambooToolWindowPanel = BambooTableToolWindowPanel.getInstance(project, projectConfigurationBean);
192 			this.crucibleToolWindowPanel = new CrucibleTableToolWindowPanel(project,
193 					projectConfigurationBean, crucibleStatusChecker);
194 			this.jiraToolWindowPanel = JIRAToolWindowPanel.getInstance(project, projectConfigurationBean, cfgManager);
195 
196 			// create tool window on the right
197             toolWindow = new PluginToolWindow(toolWindowManager, project, cfgManager);
198             Icon toolWindowIcon = IconLoader.getIcon(THE_PLUGIN_TOOL_WINDOW_ICON);
199             toolWindow.getIdeaToolWindow().setIcon(toolWindowIcon);
200 
201             // create tool window content
202 
203             toolWindow.registerPanel(PluginToolWindow.ToolWindowPanels.BAMBOO);
204             TableView.restore(projectConfigurationBean.getBambooConfiguration().getTableConfiguration(),
205                     bambooToolWindowPanel.getTable());
206 
207 
208             toolWindow.registerPanel(PluginToolWindow.ToolWindowPanels.CRUCIBLE);
209 
210 
211             toolWindow.registerPanel(PluginToolWindow.ToolWindowPanels.JIRA);
212 
213 			TableView.restore(projectConfigurationBean.getJiraConfiguration().getTableConfiguration(),
214                     jiraToolWindowPanel.getTable());
215 
216 			IdeaHelper.getAppComponent().getSchedulableCheckers().add(bambooStatusChecker);
217             // add tool window bamboo content listener to bamboo checker thread
218             bambooStatusChecker.registerListener(bambooToolWindowPanel);
219 
220 			// create Bamboo status bar icon
221             statusBarBambooIcon = new BambooStatusIcon(this.project, cfgManager);
222             statusBarBambooIcon.updateBambooStatus(BuildStatus.UNKNOWN, new BambooPopupInfo());
223 
224             // add icon listener to bamboo checker thread
225 			final StausIconBambooListener iconBambooStatusListener = new StausIconBambooListener(statusBarBambooIcon);
226             bambooStatusChecker.registerListener(iconBambooStatusListener);
227 
228             // add simple bamboo listener to bamboo checker thread
229             // this listener shows idea tooltip when buld failed
230             BambooStatusDisplay buildFailedToolTip = new BuildStatusChangedToolTip(project);
231             tooltipBambooStatusListener = new BambooStatusTooltipListener(buildFailedToolTip, cfgManager);
232             bambooStatusChecker.registerListener(tooltipBambooStatusListener);
233 
234             // add bamboo icon to status bar
235             statusBarBambooIcon.showOrHideIcon();
236 
237             // setup Crucible status checker and listeners
238 			IdeaHelper.getAppComponent().getSchedulableCheckers().add(crucibleStatusChecker);
239             crucibleStatusChecker.registerListener(crucibleToolWindowPanel);
240             // create crucible status bar icon
241             statusBarCrucibleIcon = new CrucibleStatusIcon(project, cfgManager);
242 
243 			registerCrucibleNotifier();
244 
245 			// add crucible icon to status bar
246             //statusBar.addCustomIndicationComponent(statusBarCrucibleIcon);
247             statusBarCrucibleIcon.showOrHideIcon();
248 
249             statusPluginUpdateIcon = new PluginUpdateIcon(project, pluginConfiguration, cfgManager);
250             ConfirmPluginUpdateHandler.getInstance().setDisplay(statusPluginUpdateIcon);
251             //statusPluginUpdateIcon.showOrHideIcon();
252 
253             toolWindow.showHidePanels();
254             // focus last active panel only if it exists (do not create panel)
255             PluginToolWindow.focusPanelIfExists(project, projectConfigurationBean.getActiveToolWindowTab());
256 
257             IdeaHelper.getAppComponent().rescheduleStatusCheckers(false);
258 
259 			jiraToolWindowPanel.selectLastActiveServer();
260 
261 			configurationListener = new ConfigurationListenerImpl();
262 			cfgManager.addProjectConfigurationListener(CfgUtil.getProjectId(project), configurationListener);
263 
264 			created = true;
265         }
266     }
267 
268 	public void registerCrucibleNotifier() {
269 		if (crucibleReviewNotifier == null) {
270 			crucibleReviewNotifier = new CrucibleReviewNotifier(project);
271 		}
272 
273 		if (pluginConfiguration.getCrucibleConfigurationData().getCrucibleTooltipOption()
274 				!= CrucibleTooltipOption.NEVER) {
275 
276 			if (!crucibleStatusChecker.getListenerList().contains(crucibleReviewNotifier)) {
277 				final CrucibleNotificationTooltip crucibleNotificationTooltip = new CrucibleNotificationTooltip(
278 					statusBarCrucibleIcon, project);
279 
280 				crucibleReviewNotifier.registerListener(crucibleNotificationTooltip);
281 				crucibleStatusChecker.registerListener(crucibleReviewNotifier);
282 			}
283 
284 		} else {
285 			crucibleStatusChecker.unregisterListener(crucibleReviewNotifier);
286 		}
287 	}
288 
289 	public Content createBambooContent() {
290         PeerFactory peerFactory = PeerFactory.getInstance();
291 
292         Content content = peerFactory.getContentFactory().createContent(
293                 bambooToolWindowPanel,
294                 PluginToolWindow.ToolWindowPanels.BAMBOO.toString(),
295                 false);
296 
297         content.setIcon(IconLoader.getIcon("/icons/tab_bamboo.png"));
298         content.putUserData(com.intellij.openapi.wm.ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
299 
300         return content;
301     }
302 
303 
304 	public Content createCrucibleContent() {
305         PeerFactory peerFactory = PeerFactory.getInstance();
306 
307         Content content = peerFactory.getContentFactory().createContent(
308                 crucibleToolWindowPanel, PluginToolWindow.ToolWindowPanels.CRUCIBLE.toString(), false);
309         content.setIcon(IconLoader.getIcon("/icons/tab_crucible.png"));
310         content.putUserData(com.intellij.openapi.wm.ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
311 
312         return content;
313     }
314 
315 
316     public Content createJiraContent() {
317         PeerFactory peerFactory = PeerFactory.getInstance();
318 
319         Content content = peerFactory.getContentFactory().createContent(
320                 jiraToolWindowPanel, PluginToolWindow.ToolWindowPanels.JIRA.toString(), false);
321         content.setIcon(IconLoader.getIcon("/icons/tab_jira.png"));
322         content.putUserData(com.intellij.openapi.wm.ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
323 
324         return content;
325     }
326 
327 	public void projectOpened() {
328         // content moved to StartupManager to wait until
329 		// here we have guarantee that IDEA splash screen will not obstruct our window
330 		askForUserStatistics();
331 	}
332 
333 	private void askForUserStatistics() {
334 		if (pluginConfiguration.getGeneralConfigurationData().getAnonymousFeedbackEnabled() == null) {
335 			int answer = Messages.showYesNoDialog("We would greatly appreciate if you allow us to collect anonymous "
336 					+ "usage statistics to help us provide a better quality product. Is this ok?",
337 					PluginUtil.getInstance().getName() + " request", Messages.getQuestionIcon());
338 			pluginConfiguration.getGeneralConfigurationData().setAnonymousFeedbackEnabled(answer == DialogWrapper.OK_EXIT_CODE);
339 		}
340 	}
341 
342 	public void projectClosed() {
343 		if (created) {
344 			// remove icon from status bar
345 			statusBarBambooIcon.hideIcon();
346 			statusBarBambooIcon = null;
347 			statusBarCrucibleIcon.hideIcon();
348 			statusBarCrucibleIcon = null;
349 			statusPluginUpdateIcon.hideIcon();
350 			statusPluginUpdateIcon = null;
351 
352 			IdeaHelper.getAppComponent().getSchedulableCheckers().remove(bambooStatusChecker);
353 			IdeaHelper.getAppComponent().getSchedulableCheckers().remove(crucibleStatusChecker);
354 			IdeaHelper.getAppComponent().rescheduleStatusCheckers(true);
355 			// unregister listeners
356 			//bambooStatusChecker.unregisterListener(iconBambooStatusListener);
357 			//bambooStatusChecker.unregisterListener(toolWindowBambooListener);
358 			bambooStatusChecker.unregisterListener(tooltipBambooStatusListener);
359 			crucibleStatusChecker.unregisterListener(crucibleToolWindowPanel);
360 			crucibleStatusChecker.unregisterListener(crucibleReviewNotifier);
361 			cfgManager.removeProjectConfigurationListener(CfgUtil.getProjectId(project), configurationListener);
362 
363 			// remove tool window
364 			toolWindowManager.unregisterToolWindow(PluginToolWindow.TOOL_WINDOW_NAME);
365 
366 			created = false;
367 		}
368 	}
369 
370     public ProjectConfigurationBean getState() {
371         return projectConfigurationBean;
372     }
373 
374 
375 
376 	public void loadState(ProjectConfigurationBean state) {
377         projectConfigurationBean.copyConfiguration(state);
378 	}
379 
380     public ProjectConfigurationBean getProjectConfigurationBean() {
381         return projectConfigurationBean;
382     }
383 
384     public JIRAServer getCurrentJiraServer() {
385         return currentJiraServer;
386     }
387 
388     public void setCurrentJiraServer(JIRAServer currentJiraServer) {
389         this.currentJiraServer = currentJiraServer;
390     }
391 
392     public CrucibleStatusChecker getCrucibleStatusChecker() {
393         return crucibleStatusChecker;
394     }
395 
396 
397 	public BambooStatusChecker getBambooStatusChecker() {
398         return bambooStatusChecker;
399     }
400 
401 	private class ConfigurationListenerImpl implements ConfigurationListener {
402 		public void configurationUpdated(final ProjectConfiguration aProjectConfiguration) {
403 			// show-hide icons if necessary
404 			statusBarBambooIcon.showOrHideIcon();
405 			statusBarCrucibleIcon.showOrHideIcon();
406 			// show-hide panels if necessary
407 			toolWindow.showHidePanels();
408 		}
409 
410 		public void projectUnregistered() {
411 		}
412 	}
413 }