1 /*******************************************************************************
2  * Copyright (c) 2005, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Markus Schorn (Wind River Systems) -  bug 284447
14  *     Christian Georgi (SAP)             -  bug 432480
15  *     Denis Zygann <d.zygann@web.de>      - bug 457390
16  *     Patrik Suzzi <psuzzi@gmail.com> - Bug 502050
17  *******************************************************************************/
18 package org.eclipse.ui.internal.ide.application;
19 
20 import java.net.URL;
21 import java.util.ArrayList;
22 import java.util.LinkedHashMap;
23 import java.util.List;
24 import java.util.StringJoiner;
25 
26 import org.eclipse.core.resources.IFile;
27 import org.eclipse.core.runtime.IAdaptable;
28 import org.eclipse.core.runtime.IPath;
29 import org.eclipse.core.runtime.IProduct;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.Platform;
32 import org.eclipse.core.runtime.Status;
33 import org.eclipse.jface.action.ToolBarManager;
34 import org.eclipse.jface.dialogs.ErrorDialog;
35 import org.eclipse.jface.dialogs.IDialogConstants;
36 import org.eclipse.jface.dialogs.MessageDialog;
37 import org.eclipse.jface.dialogs.MessageDialogWithToggle;
38 import org.eclipse.jface.preference.IPreferenceStore;
39 import org.eclipse.jface.resource.JFaceResources;
40 import org.eclipse.jface.util.IPropertyChangeListener;
41 import org.eclipse.osgi.util.NLS;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.dnd.FileTransfer;
44 import org.eclipse.swt.graphics.Color;
45 import org.eclipse.swt.layout.GridLayout;
46 import org.eclipse.swt.widgets.Composite;
47 import org.eclipse.swt.widgets.Control;
48 import org.eclipse.swt.widgets.Display;
49 import org.eclipse.swt.widgets.Label;
50 import org.eclipse.swt.widgets.Shell;
51 import org.eclipse.swt.widgets.ToolBar;
52 import org.eclipse.ui.IEditorInput;
53 import org.eclipse.ui.IEditorPart;
54 import org.eclipse.ui.IEditorReference;
55 import org.eclipse.ui.IFileEditorInput;
56 import org.eclipse.ui.IPageListener;
57 import org.eclipse.ui.IPartListener2;
58 import org.eclipse.ui.IPerspectiveDescriptor;
59 import org.eclipse.ui.IPerspectiveRegistry;
60 import org.eclipse.ui.IPropertyListener;
61 import org.eclipse.ui.IWorkbench;
62 import org.eclipse.ui.IWorkbenchPage;
63 import org.eclipse.ui.IWorkbenchPartConstants;
64 import org.eclipse.ui.IWorkbenchPartReference;
65 import org.eclipse.ui.IWorkbenchWindow;
66 import org.eclipse.ui.PartInitException;
67 import org.eclipse.ui.PerspectiveAdapter;
68 import org.eclipse.ui.PlatformUI;
69 import org.eclipse.ui.WorkbenchException;
70 import org.eclipse.ui.actions.ActionFactory;
71 import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
72 import org.eclipse.ui.application.ActionBarAdvisor;
73 import org.eclipse.ui.application.IActionBarConfigurer;
74 import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
75 import org.eclipse.ui.application.WorkbenchWindowAdvisor;
76 import org.eclipse.ui.ide.FileStoreEditorInput;
77 import org.eclipse.ui.internal.ide.AboutInfo;
78 import org.eclipse.ui.internal.ide.EditorAreaDropAdapter;
79 import org.eclipse.ui.internal.ide.IDEInternalPreferences;
80 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
81 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
82 import org.eclipse.ui.internal.ide.WorkbenchActionBuilder;
83 import org.eclipse.ui.internal.ide.dialogs.WelcomeEditorInput;
84 import org.eclipse.ui.internal.tweaklets.TitlePathUpdater;
85 import org.eclipse.ui.internal.tweaklets.Tweaklets;
86 import org.eclipse.ui.part.EditorInputTransfer;
87 import org.eclipse.ui.part.MarkerTransfer;
88 import org.eclipse.ui.part.ResourceTransfer;
89 import org.eclipse.ui.statushandlers.StatusManager;
90 import org.osgi.framework.Bundle;
91 import org.osgi.framework.BundleException;
92 
93 /**
94  * Window-level advisor for the IDE.
95  */
96 public class IDEWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
97 
98 	private static final String WELCOME_EDITOR_ID = "org.eclipse.ui.internal.ide.dialogs.WelcomeEditor"; //$NON-NLS-1$
99 
100 	private IDEWorkbenchAdvisor wbAdvisor;
101 	private boolean editorsAndIntrosOpened = false;
102 	private IEditorPart lastActiveEditor = null;
103 	private IPerspectiveDescriptor lastPerspective = null;
104 
105 	private IWorkbenchPage lastActivePage;
106 	private String lastEditorTitleTooltip = ""; //$NON-NLS-1$
107 
108 	private IPropertyListener editorPropertyListener = (source, propId) -> {
109 		if (propId == IWorkbenchPartConstants.PROP_TITLE) {
110 			if (lastActiveEditor != null) {
111 				String newTitle = lastActiveEditor.getTitleToolTip();
112 				if (!lastEditorTitleTooltip.equals(newTitle)) {
113 					recomputeTitle();
114 				}
115 			}
116 		}
117 	};
118 
119 	private IAdaptable lastInput;
120 	private IWorkbenchAction openPerspectiveAction;
121 
122 	/**
123 	 * The property change listener.
124 	 * @since 3.6.1
125 	 */
126 	private IPropertyChangeListener propertyChangeListener;
127 
128 	private TitlePathUpdater titlePathUpdater;
129 
130 	/**
131 	 * Crates a new IDE workbench window advisor.
132 	 *
133 	 * @param wbAdvisor
134 	 *            the workbench advisor
135 	 * @param configurer
136 	 *            the window configurer
137 	 */
IDEWorkbenchWindowAdvisor(IDEWorkbenchAdvisor wbAdvisor, IWorkbenchWindowConfigurer configurer)138 	public IDEWorkbenchWindowAdvisor(IDEWorkbenchAdvisor wbAdvisor,
139 			IWorkbenchWindowConfigurer configurer) {
140 		super(configurer);
141 		this.wbAdvisor = wbAdvisor;
142 		titlePathUpdater = (TitlePathUpdater) Tweaklets.get(TitlePathUpdater.KEY);
143 	}
144 
145 	@Override
createActionBarAdvisor( IActionBarConfigurer configurer)146 	public ActionBarAdvisor createActionBarAdvisor(
147 			IActionBarConfigurer configurer) {
148 		return new WorkbenchActionBuilder(configurer);
149 	}
150 
151 	/**
152 	 * Returns the workbench.
153 	 *
154 	 * @return the workbench
155 	 */
getWorkbench()156 	private IWorkbench getWorkbench() {
157 		return getWindowConfigurer().getWorkbenchConfigurer().getWorkbench();
158 	}
159 
160 	@Override
preWindowShellClose()161 	public boolean preWindowShellClose() {
162 		if (getWorkbench().getWorkbenchWindowCount() > 1) {
163 			return true;
164 		}
165 		// the user has asked to close the last window, while will cause the
166 		// workbench to close in due course - prompt the user for confirmation
167 		return promptOnExit(getWindowConfigurer().getWindow().getShell());
168 	}
169 
170 	/**
171 	 * Asks the user whether the workbench should really be closed. Only asks if
172 	 * the preference is enabled.
173 	 *
174 	 * @param parentShell
175 	 *            the parent shell to use for the confirmation dialog
176 	 * @return <code>true</code> if OK to exit, <code>false</code> if the user
177 	 *         canceled
178 	 * @since 3.6
179 	 */
promptOnExit(Shell parentShell)180 	static boolean promptOnExit(Shell parentShell) {
181 		IPreferenceStore store = IDEWorkbenchPlugin.getDefault()
182 				.getPreferenceStore();
183 		boolean promptOnExit = store
184 				.getBoolean(IDEInternalPreferences.EXIT_PROMPT_ON_CLOSE_LAST_WINDOW);
185 
186 		if (promptOnExit) {
187 			if (parentShell == null) {
188 				IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
189 				if (workbenchWindow != null) {
190 					parentShell = workbenchWindow.getShell();
191 				}
192 			}
193 			if (parentShell != null) {
194 				parentShell.setMinimized(false);
195 				parentShell.forceActive();
196 			}
197 
198 			String message;
199 
200 			String productName = null;
201 			IProduct product = Platform.getProduct();
202 			if (product != null) {
203 				productName = product.getName();
204 			}
205 			if (productName == null) {
206 				message = IDEWorkbenchMessages.PromptOnExitDialog_message0;
207 			} else {
208 				message = NLS.bind(
209 						IDEWorkbenchMessages.PromptOnExitDialog_message1,
210 						productName);
211 			}
212 
213 			// use of LinkedHashMap to preserve insertion order
214 			LinkedHashMap<String, Integer> buttonLabelToIdMap = new LinkedHashMap<>();
215 			buttonLabelToIdMap.put(IDEWorkbenchMessages.PromptOnExitDialog_button_label_exit, IDialogConstants.OK_ID);
216 			buttonLabelToIdMap.put(IDialogConstants.CANCEL_LABEL, IDialogConstants.CANCEL_ID);
217 			MessageDialogWithToggle dlg =
218 					new MessageDialogWithToggle(
219 							parentShell,
220 							IDEWorkbenchMessages.PromptOnExitDialog_shellTitle,
221 							null,
222 							message, MessageDialog.CONFIRM, buttonLabelToIdMap, 0,
223 							IDEWorkbenchMessages.PromptOnExitDialog_choice, false);
224 			dlg.open();
225 			if (dlg.getReturnCode() != IDialogConstants.OK_ID) {
226 				return false;
227 			}
228 			if (dlg.getToggleState()) {
229 				store
230 						.setValue(
231 								IDEInternalPreferences.EXIT_PROMPT_ON_CLOSE_LAST_WINDOW,
232 								false);
233 				IDEWorkbenchPlugin.getDefault().savePluginPreferences();
234 			}
235 		}
236 
237 		return true;
238 	}
239 
240 	@Override
preWindowOpen()241 	public void preWindowOpen() {
242 		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
243 
244 		// show the shortcut bar and progress indicator, which are hidden by
245 		// default
246 		configurer.setShowPerspectiveBar(true);
247 		configurer.setShowProgressIndicator(true);
248 
249 		// add the drag and drop support for the editor area
250 		configurer.addEditorAreaTransfer(EditorInputTransfer.getInstance());
251 		configurer.addEditorAreaTransfer(ResourceTransfer.getInstance());
252 		configurer.addEditorAreaTransfer(FileTransfer.getInstance());
253 		configurer.addEditorAreaTransfer(MarkerTransfer.getInstance());
254 		configurer.configureEditorAreaDropListener(new EditorAreaDropAdapter(
255 				configurer.getWindow()));
256 
257 		hookTitleUpdateListeners(configurer);
258 	}
259 
260 	/**
261 	 * Hooks the listeners needed on the window
262 	 *
263 	 * @param configurer
264 	 */
hookTitleUpdateListeners(IWorkbenchWindowConfigurer configurer)265 	private void hookTitleUpdateListeners(IWorkbenchWindowConfigurer configurer) {
266 		// hook up the listeners to update the window title
267 		configurer.getWindow().addPageListener(new IPageListener() {
268 			@Override
269 			public void pageActivated(IWorkbenchPage page) {
270 				updateTitle(false);
271 			}
272 
273 			@Override
274 			public void pageClosed(IWorkbenchPage page) {
275 				updateTitle(false);
276 			}
277 
278 			@Override
279 			public void pageOpened(IWorkbenchPage page) {
280 				// do nothing
281 			}
282 		});
283 		configurer.getWindow().addPerspectiveListener(new PerspectiveAdapter() {
284 			@Override
285 			public void perspectiveActivated(IWorkbenchPage page,
286 					IPerspectiveDescriptor perspective) {
287 				updateTitle(false);
288 			}
289 
290 			@Override
291 			public void perspectiveSavedAs(IWorkbenchPage page,
292 					IPerspectiveDescriptor oldPerspective,
293 					IPerspectiveDescriptor newPerspective) {
294 				updateTitle(false);
295 			}
296 
297 			@Override
298 			public void perspectiveDeactivated(IWorkbenchPage page,
299 					IPerspectiveDescriptor perspective) {
300 				updateTitle(false);
301 			}
302 		});
303 		configurer.getWindow().getPartService().addPartListener(
304 				new IPartListener2() {
305 					@Override
306 					public void partActivated(IWorkbenchPartReference ref) {
307 						if (ref instanceof IEditorReference) {
308 							updateTitle(false);
309 						}
310 					}
311 
312 					@Override
313 					public void partBroughtToTop(IWorkbenchPartReference ref) {
314 						if (ref instanceof IEditorReference) {
315 							updateTitle(false);
316 						}
317 					}
318 
319 					@Override
320 					public void partClosed(IWorkbenchPartReference ref) {
321 						updateTitle(false);
322 					}
323 
324 					@Override
325 					public void partDeactivated(IWorkbenchPartReference ref) {
326 						// do nothing
327 					}
328 
329 					@Override
330 					public void partOpened(IWorkbenchPartReference ref) {
331 						// do nothing
332 					}
333 
334 					@Override
335 					public void partHidden(IWorkbenchPartReference ref) {
336 						if (ref.getPart(false) == lastActiveEditor
337 								&& lastActiveEditor != null) {
338 							updateTitle(true);
339 						}
340 					}
341 
342 					@Override
343 					public void partVisible(IWorkbenchPartReference ref) {
344 						if (ref.getPart(false) == lastActiveEditor
345 								&& lastActiveEditor != null) {
346 							updateTitle(false);
347 						}
348 					}
349 
350 					@Override
351 					public void partInputChanged(IWorkbenchPartReference ref) {
352 						// do nothing
353 					}
354 				});
355 
356 		// Listen for changes of the workspace name.
357 		propertyChangeListener = event -> {
358 			String property = event.getProperty();
359 			if (IDEInternalPreferences.WORKSPACE_NAME.equals(property)
360 					|| IDEInternalPreferences.SHOW_LOCATION.equals(property)
361 					|| IDEInternalPreferences.SHOW_LOCATION_NAME.equals(property)
362 					|| IDEInternalPreferences.SHOW_PERSPECTIVE_IN_TITLE.equals(property)
363 					|| IDEInternalPreferences.SHOW_PRODUCT_IN_TITLE.equals(property)) {
364 				// Make sure the title is actually updated by
365 				// setting last active page.
366 				lastActivePage = null;
367 				updateTitle(false);
368 			}
369 		};
370 		IDEWorkbenchPlugin.getDefault().getPreferenceStore()
371 				.addPropertyChangeListener(propertyChangeListener);
372 	}
373 
computeTitle()374 	private String computeTitle() {
375 		StringJoiner sj = new StringJoiner(" - "); //$NON-NLS-1$
376 
377 		IPreferenceStore ps = IDEWorkbenchPlugin.getDefault().getPreferenceStore();
378 
379 		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
380 		IWorkbenchPage currentPage = configurer.getWindow().getActivePage();
381 		IEditorPart activeEditor = null;
382 		if (currentPage != null) {
383 			activeEditor = lastActiveEditor;
384 		}
385 
386 		// show workspace name
387 		if (ps.getBoolean(IDEInternalPreferences.SHOW_LOCATION_NAME)) {
388 			String workspaceName = ps.getString(IDEInternalPreferences.WORKSPACE_NAME);
389 			if (workspaceName != null && workspaceName.length() > 0) {
390 				sj.add(workspaceName);
391 			}
392 		}
393 
394 		// perspective name
395 		if (ps.getBoolean(IDEInternalPreferences.SHOW_PERSPECTIVE_IN_TITLE)) {
396 			IPerspectiveDescriptor persp = currentPage.getPerspective();
397 			if (persp != null) {
398 				sj.add(persp.getLabel());
399 			}
400 		}
401 
402 		// active editor
403 		if (currentPage != null) {
404 			if (activeEditor != null) {
405 				sj.add(activeEditor.getTitleToolTip());
406 			}
407 		}
408 
409 		// workspace location is non null either when SHOW_LOCATION is true or
410 		// when forcing -showlocation via command line
411 		String workspaceLocation = wbAdvisor.getWorkspaceLocation();
412 		if (workspaceLocation != null) {
413 			sj.add(workspaceLocation);
414 		}
415 
416 		// Application (product) name
417 		if (ps.getBoolean(IDEInternalPreferences.SHOW_PRODUCT_IN_TITLE)) {
418 			IProduct product = Platform.getProduct();
419 			if (product != null) {
420 				sj.add(product.getName());
421 			}
422 		}
423 
424 		return sj.toString();
425 	}
426 
recomputeTitle()427 	private void recomputeTitle() {
428 		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
429 		String oldTitle = configurer.getTitle();
430 		String newTitle = computeTitle();
431 		if (!newTitle.equals(oldTitle)) {
432 			configurer.setTitle(newTitle);
433 		}
434 		setTitlePath();
435 	}
436 
setTitlePath()437 	private void setTitlePath() {
438 
439 		String titlePath = null;
440 		if (lastActiveEditor != null) {
441 			IEditorInput editorInput = lastActiveEditor.getEditorInput();
442 			if (editorInput instanceof IFileEditorInput) {
443 				titlePath = computeTitlePath((IFileEditorInput) editorInput);
444 			} else if (editorInput instanceof FileStoreEditorInput) {
445 				titlePath = computeTitlePath((FileStoreEditorInput) editorInput);
446 			}
447 		}
448 		titlePathUpdater.updateTitlePath(getWindowConfigurer().getWindow().getShell(), titlePath);
449 	}
450 
computeTitlePath(FileStoreEditorInput editorInput)451 	private String computeTitlePath(FileStoreEditorInput editorInput) {
452 		return editorInput.getURI().getPath();
453 	}
454 
computeTitlePath(IFileEditorInput editorInput)455 	private String computeTitlePath(IFileEditorInput editorInput) {
456 		IFile file = editorInput.getFile();
457 		IPath location = file.getLocation();
458 		if (location != null) {
459 			return location.toFile().toString();
460 		}
461 		return null;
462 	}
463 
464 	/**
465 	 * Updates the window title. Format will be: [pageInput -]
466 	 * [currentPerspective -] [editorInput -] [workspaceLocation -] productName
467 	 * @param editorHidden TODO
468 	 */
updateTitle(boolean editorHidden)469 	private void updateTitle(boolean editorHidden) {
470 		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
471 		IWorkbenchWindow window = configurer.getWindow();
472 		IEditorPart activeEditor = null;
473 		IWorkbenchPage currentPage = window.getActivePage();
474 		IPerspectiveDescriptor persp = null;
475 		IAdaptable input = null;
476 
477 		if (currentPage != null) {
478 			activeEditor = currentPage.getActiveEditor();
479 			persp = currentPage.getPerspective();
480 			input = currentPage.getInput();
481 		}
482 
483 		if (editorHidden) {
484 			activeEditor = null;
485 		}
486 
487 		// Nothing to do if the editor hasn't changed
488 		if (activeEditor == lastActiveEditor && currentPage == lastActivePage
489 				&& persp == lastPerspective && input == lastInput) {
490 			return;
491 		}
492 
493 		if (lastActiveEditor != null) {
494 			lastActiveEditor.removePropertyListener(editorPropertyListener);
495 		}
496 
497 		if (window.isClosing()) {
498 			return;
499 		}
500 
501 		lastActiveEditor = activeEditor;
502 		lastActivePage = currentPage;
503 		lastPerspective = persp;
504 		lastInput = input;
505 
506 		if (activeEditor != null) {
507 			activeEditor.addPropertyListener(editorPropertyListener);
508 		}
509 
510 		recomputeTitle();
511 	}
512 
513 	@Override
postWindowRestore()514 	public void postWindowRestore() throws WorkbenchException {
515 		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
516 		IWorkbenchWindow window = configurer.getWindow();
517 
518 		int index = getWorkbench().getWorkbenchWindowCount() - 1;
519 
520 		AboutInfo[] welcomePerspectiveInfos = wbAdvisor
521 				.getWelcomePerspectiveInfos();
522 		if (index >= 0 && welcomePerspectiveInfos != null
523 				&& index < welcomePerspectiveInfos.length) {
524 			// find a page that exist in the window
525 			IWorkbenchPage page = window.getActivePage();
526 			if (page == null) {
527 				IWorkbenchPage[] pages = window.getPages();
528 				if (pages != null && pages.length > 0) {
529 					page = pages[0];
530 				}
531 			}
532 
533 			// if the window does not contain a page, create one
534 			String perspectiveId = welcomePerspectiveInfos[index]
535 					.getWelcomePerspectiveId();
536 			if (page == null) {
537 				IAdaptable root = wbAdvisor.getDefaultPageInput();
538 				page = window.openPage(perspectiveId, root);
539 			} else {
540 				IPerspectiveRegistry reg = getWorkbench()
541 						.getPerspectiveRegistry();
542 				IPerspectiveDescriptor desc = reg
543 						.findPerspectiveWithId(perspectiveId);
544 				if (desc != null) {
545 					page.setPerspective(desc);
546 				}
547 			}
548 
549 			// set the active page and open the welcome editor
550 			window.setActivePage(page);
551 			page.openEditor(new WelcomeEditorInput(
552 					welcomePerspectiveInfos[index]), WELCOME_EDITOR_ID, true);
553 		}
554 		cleanUpEditorArea();
555 	}
556 
557 	/**
558 	 * Tries to open the intro, if one exists and otherwise will open the legacy
559 	 * Welcome pages.
560 	 *
561 	 * @see org.eclipse.ui.application.WorkbenchWindowAdvisor#openIntro()
562 	 */
563 	@Override
openIntro()564 	public void openIntro() {
565 		if (editorsAndIntrosOpened) {
566 			return;
567 		}
568 
569 		editorsAndIntrosOpened = true;
570 
571 		// don't try to open the welcome editors if there is an intro
572 		if (wbAdvisor.hasIntro()) {
573 			super.openIntro();
574 		} else {
575 			openWelcomeEditors(getWindowConfigurer().getWindow());
576 			// save any preferences changes caused by the above actions
577 			IDEWorkbenchPlugin.getDefault().savePluginPreferences();
578 		}
579 	}
580 
581 	/*
582 	 * Open the welcome editor for the primary feature and for any newly
583 	 * installed features.
584 	 */
openWelcomeEditors(IWorkbenchWindow window)585 	private void openWelcomeEditors(IWorkbenchWindow window) {
586 		if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(
587 				IDEInternalPreferences.WELCOME_DIALOG)) {
588 			// show the welcome page for the product the first time the
589 			// workbench opens
590 			IProduct product = Platform.getProduct();
591 			if (product == null) {
592 				return;
593 			}
594 
595 			AboutInfo productInfo = new AboutInfo(product);
596 			URL url = productInfo.getWelcomePageURL();
597 			if (url == null) {
598 				return;
599 			}
600 
601 			IDEWorkbenchPlugin.getDefault().getPreferenceStore().setValue(
602 					IDEInternalPreferences.WELCOME_DIALOG, false);
603 			openWelcomeEditor(window, new WelcomeEditorInput(productInfo), null);
604 		} else {
605 			// Show the welcome page for any newly installed features
606 			List<AboutInfo> welcomeFeatures = new ArrayList<>();
607 			for (AboutInfo info : wbAdvisor.getNewlyAddedBundleGroups().values()) {
608 				if (info != null && info.getWelcomePageURL() != null) {
609 					welcomeFeatures.add(info);
610 					// activate the feature plug-in so it can run some install
611 					// code
612 					String pi = info.getBrandingBundleId();
613 					if (pi != null) {
614 						// Start the bundle if there is one
615 						Bundle bundle = Platform.getBundle(pi);
616 						if (bundle != null) {
617 							try {
618 								bundle.start(Bundle.START_TRANSIENT);
619 							} catch (BundleException exception) {
620 								StatusManager.getManager().handle(new Status(IStatus.ERROR, IDEApplication.PLUGIN_ID,
621 										"Failed to load feature", exception));//$NON-NLS-1$
622 							}
623 						}
624 					}
625 				}
626 			}
627 
628 			int wCount = getWorkbench().getWorkbenchWindowCount();
629 			for (int i = 0; i < welcomeFeatures.size(); i++) {
630 				AboutInfo newInfo = welcomeFeatures.get(i);
631 				String id = newInfo.getWelcomePerspectiveId();
632 				// Other editors were already opened in postWindowRestore(..)
633 				if (id == null || i >= wCount) {
634 					openWelcomeEditor(window, new WelcomeEditorInput(newInfo),
635 							id);
636 				}
637 			}
638 		}
639 	}
640 
641 	/**
642 	 * Open a welcome editor for the given input
643 	 */
openWelcomeEditor(IWorkbenchWindow window, WelcomeEditorInput input, String perspectiveId)644 	private void openWelcomeEditor(IWorkbenchWindow window,
645 			WelcomeEditorInput input, String perspectiveId) {
646 		if (getWorkbench().getWorkbenchWindowCount() == 0) {
647 			// Something is wrong, there should be at least
648 			// one workbench window open by now.
649 			return;
650 		}
651 
652 		IWorkbenchWindow win = window;
653 		if (perspectiveId != null) {
654 			try {
655 				win = getWorkbench().openWorkbenchWindow(perspectiveId,
656 						wbAdvisor.getDefaultPageInput());
657 				if (win == null) {
658 					win = window;
659 				}
660 			} catch (WorkbenchException e) {
661 				IDEWorkbenchPlugin
662 						.log(
663 								"Error opening window with welcome perspective.", e.getStatus()); //$NON-NLS-1$
664 				return;
665 			}
666 		}
667 
668 		if (win == null) {
669 			win = getWorkbench().getWorkbenchWindows()[0];
670 		}
671 
672 		IWorkbenchPage page = win.getActivePage();
673 		String id = perspectiveId;
674 		if (id == null) {
675 			id = getWorkbench().getPerspectiveRegistry()
676 					.getDefaultPerspective();
677 		}
678 
679 		if (page == null) {
680 			try {
681 				page = win.openPage(id, wbAdvisor.getDefaultPageInput());
682 			} catch (WorkbenchException e) {
683 				ErrorDialog.openError(win.getShell(),
684 						IDEWorkbenchMessages.Problems_Opening_Page, e
685 								.getMessage(), e.getStatus());
686 			}
687 		}
688 		if (page == null) {
689 			return;
690 		}
691 
692 		if (page.getPerspective() == null) {
693 			try {
694 				page = getWorkbench().showPerspective(id, win);
695 			} catch (WorkbenchException e) {
696 				ErrorDialog
697 						.openError(
698 								win.getShell(),
699 								IDEWorkbenchMessages.Workbench_openEditorErrorDialogTitle,
700 								IDEWorkbenchMessages.Workbench_openEditorErrorDialogMessage,
701 								e.getStatus());
702 				return;
703 			}
704 		}
705 
706 		page.setEditorAreaVisible(true);
707 
708 		// see if we already have an editor
709 		IEditorPart editor = page.findEditor(input);
710 		if (editor != null) {
711 			page.activate(editor);
712 			return;
713 		}
714 
715 		try {
716 			page.openEditor(input, WELCOME_EDITOR_ID);
717 		} catch (PartInitException e) {
718 			ErrorDialog
719 					.openError(
720 							win.getShell(),
721 							IDEWorkbenchMessages.Workbench_openEditorErrorDialogTitle,
722 							IDEWorkbenchMessages.Workbench_openEditorErrorDialogMessage,
723 							e.getStatus());
724 		}
725 		return;
726 	}
727 
728 	@Override
createEmptyWindowContents(Composite parent)729 	public Control createEmptyWindowContents(Composite parent) {
730 		final IWorkbenchWindow window = getWindowConfigurer().getWindow();
731 		Composite composite = new Composite(parent, SWT.NONE);
732 		composite.setLayout(new GridLayout(2, false));
733 		Display display = composite.getDisplay();
734 		Color bgCol = display
735 				.getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND);
736 		composite.setBackground(bgCol);
737 		Label label = new Label(composite, SWT.WRAP);
738 		label.setForeground(display
739 				.getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND));
740 		label.setBackground(bgCol);
741 		label.setFont(JFaceResources.getFontRegistry().getBold(
742 				JFaceResources.DEFAULT_FONT));
743 		String msg = IDEWorkbenchMessages.IDEWorkbenchAdvisor_noPerspective;
744 		label.setText(msg);
745 		ToolBarManager toolBarManager = new ToolBarManager();
746 		// TODO: should obtain the open perspective action from ActionFactory
747 		openPerspectiveAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG
748 				.create(window);
749 		toolBarManager.add(openPerspectiveAction);
750 		ToolBar toolBar = toolBarManager.createControl(composite);
751 		toolBar.setBackground(bgCol);
752 		return composite;
753 	}
754 	@Override
dispose()755 	public void dispose() {
756 		if (propertyChangeListener != null) {
757 			IDEWorkbenchPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(propertyChangeListener);
758 			propertyChangeListener = null;
759 		}
760 
761 		if (openPerspectiveAction!=null) {
762 			openPerspectiveAction.dispose();
763 			openPerspectiveAction = null;
764 		}
765 		super.dispose();
766 	}
767 
768 }
769