/******************************************************************************* * Copyright (c) 2015 Bruno Medeiros and other Contributors. * 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 * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package melnorme.lang.ide.ui.navigator; import static java.text.MessageFormat.format; import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull; import static melnorme.utilbox.core.CoreUtil.list; import static melnorme.utilbox.core.fntypes.CommonGetter.getOrNull; import java.text.MessageFormat; import org.eclipse.core.resources.IProject; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.PreferenceDialog; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IViewPart; import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.navigator.ICommonActionConstants; import melnorme.lang.ide.core.launch.BuildTargetLaunchCreator; import melnorme.lang.ide.core.operations.build.BuildManager; import melnorme.lang.ide.core.operations.build.BuildManagerMessages; import melnorme.lang.ide.core.operations.build.BuildTarget; import melnorme.lang.ide.core.operations.build.BuildTargetData; import melnorme.lang.ide.core.operations.build.ProjectBuildInfo; import melnorme.lang.ide.ui.LangUIPlugin_Actual; import melnorme.lang.ide.ui.launch.LangLaunchShortcut; import melnorme.lang.ide.ui.launch.LangLaunchShortcut.BuildTargetLaunchable; import melnorme.lang.ide.ui.navigator.LangNavigatorActionProvider.ViewPartActionGroup; import melnorme.lang.ide.ui.utils.BuildUtilities; import melnorme.lang.ide.ui.utils.UIOperationsStatusHandler; import melnorme.lang.ide.ui.utils.operations.JobUIOperation; import melnorme.lang.tooling.bundle.LaunchArtifact; import melnorme.lang.tooling.common.ops.IOperationMonitor; import melnorme.utilbox.collections.ArrayList2; import melnorme.utilbox.collections.Collection2; import melnorme.utilbox.collections.Indexable; import melnorme.utilbox.concurrency.OperationCancellation; import melnorme.utilbox.core.CommonException; import melnorme.utilbox.ownership.Disposable; import melnorme.utilbox.status.Severity; import melnorme.utilbox.status.StatusException; public abstract class BuildTargetsActionGroup extends ViewPartActionGroup { public BuildTargetsActionGroup(IViewPart viewPart) { super(viewPart); } @Override public void fillContextMenu(IMenuManager menu) { Object firstSel = getSelectionFirstElement(); if(firstSel instanceof BuildTargetsContainer) { BuildTargetsContainer buildTargetsContainer = (BuildTargetsContainer) firstSel; menu.add(new BuildAllTargetsAction(buildTargetsContainer)); menu.add(new BuildEnabledTargetsAction(buildTargetsContainer)); menu.add(new Separator("additions")); menu.add(new ConfigureBuildTargetAction(buildTargetsContainer)); } if(firstSel instanceof BuildTargetElement) { BuildTargetElement buildTargetElement = (BuildTargetElement) firstSel; menu.add(new BuildSingleTargetAction(buildTargetElement)); addLaunchActions(menu, buildTargetElement); menu.add(new Separator("configure_BuildTarget")); menu.add(new ToggleEnabledAction(buildTargetElement)); menu.add(new ToggleAutoBuildEnabledAction(buildTargetElement)); menu.add(new ConfigureBuildTargetAction(buildTargetElement)); } } protected void addLaunchActions(IMenuManager menu, BuildTargetElement buildTargetElement) { BuildTarget buildTarget = buildTargetElement.getBuildTarget(); LaunchArtifact mainLaunchArtifact = getOrNull(buildTarget::getMainLaunchArtifact); Indexable<LaunchArtifact> launchSubArtifacts = getOrNull(buildTarget::getSubLaunchArtifacts); String suggestedLaunchSuffix = buildTargetElement.getTargetDisplayName(); if(buildTarget.isDefaultBuildType()) { suggestedLaunchSuffix = null; } LaunchBuildTargetAction runTargetAction = new LaunchBuildTargetAction(buildTargetElement, true, null, suggestedLaunchSuffix, MessageFormat.format("Run {0}", buildTargetElement.getTargetDisplayName())); LaunchBuildTargetAction debugTargetAction = new LaunchBuildTargetAction(buildTargetElement, false, null, suggestedLaunchSuffix, MessageFormat.format("Debug {0}", buildTargetElement.getTargetDisplayName())); if(launchSubArtifacts == null) { if(mainLaunchArtifact != null) { menu.add(runTargetAction); menu.add(debugTargetAction); } return; } MenuManager runSubTargetsMenu = new MenuManager("Run "); MenuManager debugSubTargetsMenu = new MenuManager("Debug "); if(mainLaunchArtifact != null) { addMainArtifactAction(buildTarget, runTargetAction, debugTargetAction, runSubTargetsMenu, debugSubTargetsMenu); } for(LaunchArtifact launchArtifact : launchSubArtifacts) { String launchName = createLaunchShortcut().getLaunchNameForSubTarget(launchArtifact.getName()); String artifactPath = launchArtifact.getArtifactPath(); runSubTargetsMenu.add(new LaunchBuildTargetAction(buildTargetElement, true, artifactPath, launchName, "Run " + launchName + " - " + artifactPath + "")); debugSubTargetsMenu.add(new LaunchBuildTargetAction(buildTargetElement, false, artifactPath, launchName, "Debug " + launchName + " - " + artifactPath + "")); } menu.add(runSubTargetsMenu); menu.add(debugSubTargetsMenu); } protected void addMainArtifactAction( BuildTarget buildTarget, LaunchBuildTargetAction runTargetAction, LaunchBuildTargetAction debugTargetAction, MenuManager runSubTargetsMenu, MenuManager debugSubTargetsMenu) { if(buildTarget.isDefaultBuildType()) { runTargetAction.setText("Run default executable"); debugTargetAction.setText("Debug default executable"); } runSubTargetsMenu.add(runTargetAction); runSubTargetsMenu.add(new Separator()); debugSubTargetsMenu.add(debugTargetAction); debugSubTargetsMenu.add(new Separator()); } @Override public void fillActionBars(IActionBars actionBars) { Object firstSel = getSelectionFirstElement(); if(firstSel instanceof BuildTargetElement) { BuildTargetElement buildTargetElement = (BuildTargetElement) firstSel; fillActionBars(actionBars, buildTargetElement); } } protected void fillActionBars(IActionBars actionBars, BuildTargetElement buildTargetElement) { actionBars.setGlobalActionHandler(ICommonActionConstants.OPEN, new BuildSingleTargetAction(buildTargetElement)); } public static abstract class AbstractBuildElementAction extends Action { protected final BuildManager buildManager; protected final IProject project; protected final String opName; public AbstractBuildElementAction(BuildTargetsContainer buildTargetContainer, String opName) { this(buildTargetContainer, opName, Action.AS_UNSPECIFIED); } public AbstractBuildElementAction(BuildTargetsContainer buildTargetContainer, String opName, int style) { this(buildTargetContainer.getBuildManager(), buildTargetContainer.getProject(), opName, style); } public AbstractBuildElementAction(BuildManager buildManager, IProject project, String opName, int style) { super(opName, style); this.buildManager = assertNotNull(buildManager); this.project = assertNotNull(project); this.opName = opName; } public IProject getProject() { return project; } public BuildManager getBuildManager() { return buildManager; } public ProjectBuildInfo getBuildInfo() { return getBuildManager().getBuildInfo(getProject()); } @Override public void run() { try { doRun(); } catch(StatusException se) { UIOperationsStatusHandler.handleStatus(getStatusDialogTitle(), se); } } protected String getStatusDialogTitle() { return "Error during: " + getText(); } public void doRun() throws StatusException { try(Disposable reg = buildManager.autoBuildsEnablement().enterDisable()) { // Note: this needs to run in UI BuildUtilities.saveEditors(list(getProject())); } new JobUIOperation(getJobTitle(), this::doJobRun).execute(); } protected String getJobTitle() { return opName; } @SuppressWarnings("unused") protected void doJobRun(IOperationMonitor om) throws CommonException, OperationCancellation { } } public static class BuildAllTargetsAction extends AbstractBuildElementAction { public BuildAllTargetsAction(BuildTargetsContainer buildTargetContainer) { super(buildTargetContainer, BuildManagerMessages.NAME_BuildAllTargetsAction); } @Override protected void doJobRun(IOperationMonitor om) throws CommonException, OperationCancellation { Collection2<BuildTarget> enabledTargets = getBuildInfo().getBuildTargets(); getBuildManager().executeBuildTargetsOperation(om, getProject(), enabledTargets); } } public static class BuildEnabledTargetsAction extends AbstractBuildElementAction { public BuildEnabledTargetsAction(BuildTargetsContainer buildTargetContainer) { super(buildTargetContainer, BuildManagerMessages.NAME_BuildEnabledTargetsAction); } @Override protected void doJobRun(IOperationMonitor om) throws CommonException, OperationCancellation { ArrayList2<BuildTarget> enabledTargets = getBuildInfo().getEnabledTargets(true); getBuildManager().executeBuildTargetsOperation(om, getProject(), enabledTargets); } } /* ----------------- ----------------- */ public static abstract class AbstractBuildTargetAction extends AbstractBuildElementAction { protected final BuildTargetElement buildTargetElement; protected final BuildTarget buildTarget; public AbstractBuildTargetAction(BuildTargetElement buildTargetElement, String text) { this(buildTargetElement, text, Action.AS_UNSPECIFIED); } public AbstractBuildTargetAction(BuildTargetElement buildTargetElement, String text, int style) { super(buildTargetElement.getBuildManager(), buildTargetElement.project, text, style); this.buildTargetElement = assertNotNull(buildTargetElement); this.buildTarget = buildTargetElement.getBuildTarget(); } protected String getBuildTargetName() { return buildTarget.getBuildTargetName(); } } public static class ToggleEnabledAction extends AbstractBuildTargetAction { public ToggleEnabledAction(BuildTargetElement buildTargetElement) { super(buildTargetElement, BuildManagerMessages.LABEL_EnableForNormalBuild, Action.AS_CHECK_BOX); setChecked(buildTarget.isNormalBuildEnabled()); } @Override public void doRun() throws StatusException { try { doRun0(); } catch(CommonException e) { throw e.toStatusException(Severity.ERROR); } } protected void doRun0() throws CommonException { getBuildInfo().changeEnable(getBuildTargetName(), isChecked(), buildTarget.isAutoBuildEnabled()); } } public static class ToggleAutoBuildEnabledAction extends ToggleEnabledAction { public ToggleAutoBuildEnabledAction(BuildTargetElement buildTargetElement) { super(buildTargetElement); setText(BuildManagerMessages.LABEL_EnableForAutoBuild); setChecked(buildTarget.isAutoBuildEnabled()); } @Override protected void doRun0() throws CommonException { getBuildInfo().changeEnable(getBuildTargetName(), buildTarget.isNormalBuildEnabled(), isChecked()); } } public static class BuildSingleTargetAction extends AbstractBuildTargetAction { public BuildSingleTargetAction(BuildTargetElement buildTargetElement) { super(buildTargetElement, BuildManagerMessages.NAME_RunBuildTargetAction); } @Override protected String getJobTitle() { return format(BuildManagerMessages.INFO_BuildTargetAction, getProject().getName(), buildTargetElement.getTargetDisplayName()); } @Override public void doRun() throws StatusException { super.doRun(); } @Override protected void doJobRun(IOperationMonitor om) throws CommonException, OperationCancellation { getBuildManager().executeBuildTargetOperation(om, getProject(), buildTarget); } } public class LaunchBuildTargetAction extends AbstractBuildTargetAction { public String mode; public BuildTargetLaunchCreator launchCreator; public LaunchBuildTargetAction(BuildTargetElement buildTargetElement, boolean isRun, String exePathOverride, String launchNameSuggestion, String actionText) { super(buildTargetElement, ""); mode = isRun ? "run" : "debug"; setText(actionText); String targetName = buildTarget.getTargetName(); launchCreator = buildTargetLaunchCreator(project, targetName, exePathOverride, launchNameSuggestion); } protected String getTargetName() { return buildTarget.getTargetName(); } @Override public void doRun() throws StatusException { LangLaunchShortcut launchShortcut = createLaunchShortcut(); BuildTargetLaunchable launchable = launchShortcut.new BuildTargetLaunchable(project, launchCreator); launchShortcut.launchTarget(launchable, mode); } } public static BuildTargetLaunchCreator buildTargetLaunchCreator(IProject project, String targetName, String executablePath, String launchNameSuffixSuggestion) { BuildTargetData buildTargetData = new BuildTargetData( targetName, false, false, null, executablePath ); return new BuildTargetLaunchCreator(project.getName(), buildTargetData, launchNameSuffixSuggestion); } protected abstract LangLaunchShortcut createLaunchShortcut(); public class ConfigureBuildTargetAction extends AbstractBuildElementAction { protected String targetName; public ConfigureBuildTargetAction(BuildTargetsContainer buildTargetContainer) { super(buildTargetContainer.getBuildManager(), buildTargetContainer.getProject(), BuildManagerMessages.NAME_ConfigureTargetsAction, Action.AS_UNSPECIFIED); } public ConfigureBuildTargetAction(BuildTargetElement buildTargetElement) { super(buildTargetElement.getBuildManager(), buildTargetElement.getProject(), BuildManagerMessages.NAME_ConfigureTargetAction, Action.AS_UNSPECIFIED); targetName = buildTargetElement.getBuildTarget().getTargetName(); } @Override public void doRun() throws StatusException { PreferenceDialog dialog = PreferencesUtil.createPropertyDialogOn(getShell(), getProject(), getProjectConfigPropertyPage(), null, targetName); dialog.open(); } } protected String getProjectConfigPropertyPage() { return LangUIPlugin_Actual.PLUGIN_ID + ".propertyPages.ProjectBuildConfiguration"; } }