/******************************************************************************* * Copyright 2011 Google Inc. All Rights Reserved. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package com.google.gdt.eclipse.suite; import com.google.gdt.eclipse.core.AbstractGwtPlugin; import com.google.gdt.eclipse.core.BuilderUtilities; import com.google.gdt.eclipse.core.CorePluginLog; import com.google.gdt.eclipse.core.Logger; import com.google.gdt.eclipse.core.markers.GdtProblemSeverities; import com.google.gdt.eclipse.core.projects.ProjectUtilities; import com.google.gdt.eclipse.suite.launch.processors.LaunchConfigAffectingChangesListener; import com.google.gdt.eclipse.suite.preferences.GdtPreferences; import com.google.gdt.eclipse.suite.resources.GdtImages; import com.google.gdt.eclipse.suite.wizards.WebAppProjectCreator; import com.google.gwt.eclipse.core.nature.GWTNature; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PerspectiveAdapter; import org.eclipse.ui.internal.Workbench; import org.eclipse.ui.internal.WorkbenchPage; import org.osgi.framework.BundleContext; import org.osgi.framework.Version; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Activator for the com.google.eclipse.gdt plugin. */ @SuppressWarnings("restriction") // org.eclipse.ui.internal.Workbench, org.eclipse.ui.internal.WorkbenchPage public class GdtPlugin extends AbstractGwtPlugin { public static final String PLUGIN_ID = "com.gwtplugins.gdt.eclipse.suite"; private static Logger logger; /** * Perspectives that we monitor and optionally add our new wizards to. */ private static final List<String> PERSPECTIVES_TO_ADD_WIZARDS_TO = new ArrayList<String>( Arrays.asList(new String[] { "org.eclipse.jdt.ui.JavaPerspective", "org.eclipse.jdt.ui.JavaBrowsingPerspective", "org.eclipse.jdt.ui.JavaHierarchyPerspective", "org.eclipse.jst.j2ee.J2EEPerspective" })); private static GdtPlugin plugin; // The following constant is referenced only in commented-out lines of the method // maybeAddNewWizardActionsToPerspective: // /** // * Wizards that we add to perspectives. // * // * TODO: If we add more wizards, this list should grow. Alternatively, we // * could query the extension registry and add all GDT contributed wizards. // */ // private static final List<String> WIZARDS_TO_ADD_TO_PERSPECTIVES = new ArrayList<String>( // Arrays.asList(new String[] { // "com.google.gdt.eclipse.suite.wizards.newProjectWizard", // "com.google.gwt.eclipse.core.newModuleWizard", // "com.google.gwt.eclipse.core.newHostPageWizard", // "com.google.gwt.eclipse.core.newEntryPointWizard", // "com.google.gwt.eclipse.core.newClientBundleWizard", // "com.google.gwt.eclipse.core.newUiBinderWizard"})); public static GdtPlugin getDefault() { return plugin; } /** * Return the current eclipse version as a string. * * @return current eclipse version as a string. */ public static String getEclipseVersion() { return ResourcesPlugin.getPlugin().getBundle().getVersion().toString(); } public static String getInstallationId() { String id = GdtPreferences.getInstallationId(); if (id == null) { // Use the current time in millis as the installation id and store it // back to the prefs. id = Long.toString(System.currentTimeMillis()); GdtPreferences.setInstallationId(id); } return id; } public static Logger getLogger() { return logger; } public static Version getVersion() { return getDefault().getBundle().getVersion(); } private static void rebuildProjectIfPluginVersionChanged(IProject project) { // We're only worried about GWT projects if (GWTNature.isGWTProject(project.getProject())) { // Find the last plugin version that know the project was built with Version lastForcedRebuildAt = GdtPreferences.getVersionForLastForcedRebuild(project); Version currentPluginVersion = GdtPlugin.getVersion(); if (!lastForcedRebuildAt.equals(currentPluginVersion)) { GdtPreferences.setVersionForLastForcedRebuild(project, currentPluginVersion); BuilderUtilities.scheduleRebuild(project); CorePluginLog.logInfo("Scheduled rebuild of project " + project.getName() + " because of plugin update (current version: " + currentPluginVersion.toString() + ")"); } } } private static void rebuildProjectsIfPluginVersionChanged() { boolean closedProjectsInWorkspace = false; // Rebuild all (open) GWT projects in the workspace IWorkspace workspace = ResourcesPlugin.getWorkspace(); for (IProject project : workspace.getRoot().getProjects()) { if (project.isOpen()) { rebuildProjectIfPluginVersionChanged(project); } else { closedProjectsInWorkspace = true; } } // Add listeners for all closed projects, so we can rebuild them, too, // when they're opened (but only if they are GWT projects). if (closedProjectsInWorkspace) { workspace.addResourceChangeListener(new IResourceChangeListener() { @Override public void resourceChanged(IResourceChangeEvent event) { IResourceDelta delta = event.getDelta(); if (delta != null) { // Find any project-level changes IResourceDelta[] projectDeltas = delta.getAffectedChildren(IResourceDelta.CHANGED, IResource.PROJECT); // The master delta may include more than one project delta for (IResourceDelta projectDelta : projectDeltas) { // Find any deltas for projects being opened/closed if ((projectDelta.getFlags() & IResourceDelta.OPEN) > 0) { IProject project = (IProject) projectDelta.getResource(); if (project.isOpen()) { rebuildProjectIfPluginVersionChanged(project); } } } } } }); } } private final PerspectiveAdapter perspectiveListener = new PerspectiveAdapter() { @Override public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspectiveDesc) { maybeAddNewWizardActionsToPerspective((WorkbenchPage) page, perspectiveDesc); } }; private final IWindowListener windowListener = new IWindowListener() { @Override public void windowActivated(IWorkbenchWindow window) { } @Override public void windowClosed(IWorkbenchWindow window) { } @Override public void windowDeactivated(IWorkbenchWindow window) { } @Override public void windowOpened(IWorkbenchWindow window) { maybeAddNewWizardActionsToWindow(window); } }; public GdtPlugin() { } @Override protected void initializeImageRegistry(ImageRegistry reg) { super.initializeImageRegistry(reg); reg.put(GdtImages.GDT_ICON, imageDescriptorFromPath("icons/gdt_16x16.png")); reg.put(GdtImages.GWT_SERVER_ICON, imageDescriptorFromPath("icons/gwt_server_16x16.png")); reg.put(GdtImages.GWT_SERVER_ICON, imageDescriptorFromPath("icons/gwt_compiler_16x16.png")); reg.put(GdtImages.GDT_NEW_PROJECT_ICON, imageDescriptorFromPath("icons/gdt-new-project_16x16.png")); reg.put(GdtImages.GDT_NEW_PROJECT_LARGE, imageDescriptorFromPath("icons/gdt-new-project_75x66.png")); } /** * If we haven't added them in the past, add the new wizard actions that this to the perspective which is being * displayed on the workbench page. * * Note: This method can only be called once the workbench has been started. */ private void maybeAddNewWizardActionsToPerspective(WorkbenchPage page, IPerspectiveDescriptor desc) { if (page == null || desc == null) { return; } if (PERSPECTIVES_TO_ADD_WIZARDS_TO.contains(desc.getId())) { // Perspective perspective = page.findPerspective(desc); // if (perspective != null) { // List<String> wizardsToAdd = new ArrayList<String>( // WIZARDS_TO_ADD_TO_PERSPECTIVES); // // // Ignore any wizards we've already tried to add to this perspective. // // That way we don't re-add any wizards that the user explicitly // // removed from the New shortcut menu. // List<String> wizardsAlreadyAdded = GdtPreferences // .getAddedNewWizardActionsForPerspective(desc.getId()); // wizardsToAdd.removeAll(wizardsAlreadyAdded); // // // Get the current set of wizard shortcuts // List<String> currentWizardShortcuts = new ArrayList<String>( // Arrays.asList(perspective.getNewWizardShortcuts())); // // // Ignore wizards that already have shortcuts in this perspective // wizardsToAdd.removeAll(currentWizardShortcuts); // // // Only update the perspective if there are new wizards to add // if (!wizardsToAdd.isEmpty()) { // currentWizardShortcuts.addAll(wizardsToAdd); // // // Update the perspective // perspective.setNewWizardActionIds(new ArrayList<String>( // currentWizardShortcuts)); // } // // // Remember the wizards that we've attempted to add to this perspective // GdtPreferences.setAddedNewWizardActionsForPerspective(desc.getId(), // WIZARDS_TO_ADD_TO_PERSPECTIVES); // } else { // assert false : "Perspective was activated but not found"; // } } } /** * Adds the new wizards to the current perspective displayed in <code>activeWorkbenchWindow</code>, if they've not * been added already. Adds listeners on the window so that the same is done whenever the user switches perspectives * in the window. * * Note: This method can only be called once the workbench has been started. */ private void maybeAddNewWizardActionsToWindow(IWorkbenchWindow activeWorkbenchWindow) { if (activeWorkbenchWindow == null) { return; } activeWorkbenchWindow.addPerspectiveListener(perspectiveListener); WorkbenchPage activePage = (WorkbenchPage) activeWorkbenchWindow.getActivePage(); if (activePage == null) { return; } IPerspectiveDescriptor perspectiveDesc = activePage.getPerspective(); maybeAddNewWizardActionsToPerspective(activePage, perspectiveDesc); } /** * Adds the new wizards to the current perspective displayed in the workbench's active window, if they've not been * added already. Adds listeners on the workbench so that the same is done for any new workbench windows that are * created. * * Note: This method can only be called once the workbench has been started. */ private void maybeAddNewWizardActionsToWorkbench() { IWorkbench workbench = Workbench.getInstance(); if (workbench != null) { workbench.addWindowListener(windowListener); maybeAddNewWizardActionsToWindow(workbench.getActiveWorkbenchWindow()); } else { // This should never happen; the workbench must be started by the time // this code is executed } } @Override public void start(BundleContext context) throws Exception { super.start(context); plugin = this; logger = new Logger(this); // Force the installation id initialization before SDK registration. getInstallationId(); GdtPreferences.registerSdks(); ProjectUtilities.setWebAppProjectCreatorFactory(WebAppProjectCreator.FACTORY); /* * Execute this on the UI thread. This has the effect of delaying the execution until the Workbench is running and * the UI is available. This is necessary because the code in this method manipulates the Workbench UI. */ Display.getDefault().asyncExec(new Runnable() { @Override public void run() { maybeAddNewWizardActionsToWorkbench(); } }); LaunchConfigAffectingChangesListener.INSTANCE.start(); /* * We've already loaded the specific problem type enums in the specific plugin activators that define them * (GWTPlugin.java). Now we need to load the problem severities. * * There is a small window between the time that this plugin is loaded and a plugin-specific builder (i.e. for GWT) * can be invoked. It may be the case that a user will get a problem marker that has a severity that * mismatches what they've defined. This will be fixed up on their next rebuild. If we hear of reports of this being * a nuisance, we can work out a clever way to rebuild possibly-affected projects when this plugin loads (or, * perhaps have a latch that prevents problem markers from being created until this plugin loads). */ GdtProblemSeverities.getInstance().loadSeverities(GdtPreferences.getEncodedProblemSeverities()); rebuildProjectsIfPluginVersionChanged(); new ProjectMigrator().migrate(); } @Override public void stop(BundleContext context) throws Exception { LaunchConfigAffectingChangesListener.INSTANCE.stop(); plugin = null; logger = null; super.stop(context); } }