/******************************************************************************* * Copyright (c) 2011, 2013 Wind River Systems, Inc. and others. * 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.internal.cdt.ui.launch; import org.eclipse.cdt.launch.ui.CMainTab; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.window.IShellProvider; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate; import org.eclipse.tcf.internal.debug.ui.launch.PeerListControl; import org.eclipse.tcf.internal.debug.ui.launch.PeerListControl.PeerInfo; import org.eclipse.tcf.internal.debug.ui.launch.RemoteFileSelectionDialog; import org.eclipse.tcf.protocol.IChannel; import org.eclipse.tcf.protocol.IChannel.IChannelListener; import org.eclipse.tcf.services.IFileSystem; import org.eclipse.tcf.services.IProcesses; import org.eclipse.tcf.util.TCFTask; import org.eclipse.ui.PlatformUI; public class RemoteCMainTab extends CMainTab implements IShellProvider { private static final String REMOTE_PATH_DEFAULT = EMPTY_STRING; private static final boolean SKIP_DOWNLOAD_TO_REMOTE_DEFAULT = false; private PeerListControl fPeerList; private Text fRemoteProgText; private Button fRemoteBrowseButton; private Button fSkipDownloadButton; // private Text fPreRunText; private boolean fIsInitializing = false; private PeerInfo fSelectedPeer; private boolean fPeerHasFileSystemService; private boolean fPeerHasProcessesService; public RemoteCMainTab() { super(false); } @Override public Shell getShell() { return super.getShell(); } public void createControl(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); GridLayout topLayout = new GridLayout(); setControl(comp); comp.setLayout(topLayout); /* TCF peer selection control */ createPeerListGroup(comp); /* The Project and local binary location */ createVerticalSpacer(comp, 1); createProjectGroup(comp, 1); createBuildConfigCombo(comp, 1); createExeFileGroup(comp, 1); /* The remote binary location and skip download option */ createVerticalSpacer(comp, 1); createTargetExePathGroup(comp); createDownloadOption(comp); /* If the local binary path changes, modify the remote binary location */ fProgText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent evt) { setLocalPathForRemotePath(); } }); PlatformUI .getWorkbench() .getHelpSystem() .setHelp(getControl(), "org.eclipse.tcf.cdt.ui.remoteApplicationLaunchGroup"); //$NON-NLS-1$ } private void createPeerListGroup(Composite comp) { new Label(comp, SWT.NONE).setText("Targets:"); fPeerList = new PeerListControl(comp); fPeerList.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { handlePeerSelectionChanged(); useDefaultsFromConnection(); updateLaunchConfigurationDialog(); } }); } public boolean isValid(ILaunchConfiguration config) { boolean valid = super.isValid(config); if (valid) { if (fSelectedPeer == null) { setErrorMessage("No target selected."); valid = false; } else if (!fPeerHasProcessesService) { setErrorMessage("Selected target does not support 'Processes' service"); valid = false; } if (valid) { String name = fRemoteProgText.getText().trim(); if (name.length() == 0) { setErrorMessage("Remote executable path is not specified."); valid = false; } } } return valid; } protected void createTargetExePathGroup(Composite parent) { Composite mainComp = new Composite(parent, SWT.NONE); GridLayout mainLayout = new GridLayout(); mainLayout.numColumns = 2; mainLayout.marginHeight = 0; mainLayout.marginWidth = 0; mainComp.setLayout(mainLayout); GridData gd = new GridData(GridData.FILL_HORIZONTAL); mainComp.setLayoutData(gd); Label remoteProgLabel = new Label(mainComp, SWT.NONE); remoteProgLabel.setText("Remote Absolute File Path for C/C++ Application:"); gd = new GridData(); gd.horizontalSpan = 2; remoteProgLabel.setLayoutData(gd); fRemoteProgText = new Text(mainComp, SWT.SINGLE | SWT.BORDER); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 1; fRemoteProgText.setLayoutData(gd); fRemoteProgText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent evt) { updateLaunchConfigurationDialog(); } }); fRemoteBrowseButton = createPushButton(mainComp, "Browse...", null); fRemoteBrowseButton.setEnabled(fPeerHasFileSystemService); fRemoteBrowseButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent evt) { handleRemoteBrowseSelected(); updateLaunchConfigurationDialog(); } }); // Commands to run before execution /* Label preRunLabel = new Label(mainComp, SWT.NONE); preRunLabel.setText("Commands to execute before application"); gd = new GridData(); gd.horizontalSpan = 2; preRunLabel.setLayoutData(gd); fPreRunText = new Text(mainComp, SWT.MULTI | SWT.BORDER); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; fPreRunText.setLayoutData(gd); fPreRunText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent evt) { updateLaunchConfigurationDialog(); } }); */ } protected void createDownloadOption(Composite parent) { Composite mainComp = new Composite(parent, SWT.NONE); GridLayout mainLayout = new GridLayout(); mainLayout.marginHeight = 0; mainLayout.marginWidth = 0; mainComp.setLayout(mainLayout); GridData gd = new GridData(GridData.FILL_HORIZONTAL); mainComp.setLayoutData(gd); fSkipDownloadButton = createCheckButton(mainComp, "Skip download to target path."); fSkipDownloadButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent evt) { updateLaunchConfigurationDialog(); } }); fSkipDownloadButton.setEnabled(fPeerHasFileSystemService); } @Override public void setDefaults(ILaunchConfigurationWorkingCopy config) { super.setDefaults(config); config.setAttribute(TCFLaunchDelegate.ATTR_RUN_LOCAL_AGENT, false); config.setAttribute(TCFLaunchDelegate.ATTR_USE_LOCAL_AGENT, false); } public void performApply(ILaunchConfigurationWorkingCopy config) { String peerId = getSelectedPeerId(); if (peerId != null) { config.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, peerId); } config.setAttribute(TCFLaunchDelegate.ATTR_RUN_LOCAL_AGENT, false); config.setAttribute(TCFLaunchDelegate.ATTR_USE_LOCAL_AGENT, false); config.setAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, fRemoteProgText.getText()); config.setAttribute(TCFLaunchDelegate.ATTR_COPY_TO_REMOTE_FILE, !fSkipDownloadButton.getSelection()); // config.setAttribute(TCFLaunchDelegate.ATTR_PRERUN_COMMANDS, fPreRunText.getText()); super.performApply(config); } public void initializeFrom(ILaunchConfiguration config) { fIsInitializing = true; super.initializeFrom(config); updatePeerFromConfig(config); updateTargetProgFromConfig(config); updateSkipDownloadFromConfig(config); fIsInitializing = false; } protected void updatePeerFromConfig(ILaunchConfiguration config) { try { String peerId = config.getAttribute(TCFLaunchDelegate.ATTR_PEER_ID, (String) null); fPeerList.setInitialSelection(peerId); } catch (CoreException e) { // Ignore } } protected void handleRemoteBrowseSelected() { RemoteFileSelectionDialog dialog = new RemoteFileSelectionDialog(this, SWT.SAVE); dialog.setSelection(fRemoteProgText.getText().trim()); dialog.setPeer(fSelectedPeer.peer); if (dialog.open() == Window.OK) { String file = dialog.getSelection(); if (file != null) { fRemoteProgText.setText(file); } } } protected void updateTargetProgFromConfig(ILaunchConfiguration config) { String targetPath = REMOTE_PATH_DEFAULT; try { targetPath = config.getAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, REMOTE_PATH_DEFAULT); } catch (CoreException e) { // Ignore } fRemoteProgText.setText(targetPath); // String prelaunchCmd = null; // try { // prelaunchCmd = config.getAttribute(TCFLaunchDelegate.ATTR_PRERUN_COMMANDS, ""); //$NON-NLS-1$ // } // catch (CoreException e) { // // Ignore // } // fPreRunText.setText(prelaunchCmd); } protected void updateSkipDownloadFromConfig(ILaunchConfiguration config) { boolean doDownload = !SKIP_DOWNLOAD_TO_REMOTE_DEFAULT; try { doDownload = config.getAttribute(TCFLaunchDelegate.ATTR_COPY_TO_REMOTE_FILE, doDownload); } catch (CoreException e) { // Ignore for now } fSkipDownloadButton.setSelection(!doDownload); } /* * setLocalPathForRemotePath This function sets the remote path text field * with the value of the local executable path. */ private void setLocalPathForRemotePath() { String programName = fProgText.getText().trim(); boolean bUpdateRemote = false; String remoteName = fRemoteProgText.getText().trim(); String remoteWsRoot = getRemoteWSRoot(); if (remoteName.length() == 0) { bUpdateRemote = true; } else if (remoteWsRoot.length() != 0) { bUpdateRemote = remoteName.equals(remoteWsRoot); } if (programName.length() != 0 && bUpdateRemote && getCProject() != null) { IProject project = getCProject().getProject(); IPath exePath = new Path(programName); if (!exePath.isAbsolute()) { exePath = project.getFile(programName).getLocation(); IPath wsRoot = project.getWorkspace().getRoot().getLocation(); exePath = makeRelativeToWSRootLocation(exePath, remoteWsRoot, wsRoot); } String path = exePath.toString(); fRemoteProgText.setText(path); } } private void useDefaultsFromConnection() { // During initialization, we don't want to use the default // values of the connection, but we want to use the ones // that are part of the configuration if (fIsInitializing) return; if ((fRemoteProgText != null) && !fRemoteProgText.isDisposed()) { String remoteName = fRemoteProgText.getText().trim(); String remoteWsRoot = getRemoteWSRoot(); if (remoteName.length() == 0) { fRemoteProgText.setText(remoteWsRoot); } else { // try to use remote path IPath wsRoot = ResourcesPlugin.getWorkspace().getRoot().getLocation(); IPath remotePath = makeRelativeToWSRootLocation(new Path(remoteName), remoteWsRoot, wsRoot); fRemoteProgText.setText(remotePath.toString()); } } boolean hasFileSystemService = hasFileSystemService(); if (fSkipDownloadButton != null && !fSkipDownloadButton.isDisposed()) { fSkipDownloadButton.setEnabled(hasFileSystemService); } if (fRemoteBrowseButton != null && !fRemoteBrowseButton.isDisposed()) { fRemoteBrowseButton.setEnabled(hasFileSystemService); } } private boolean hasFileSystemService() { return fPeerHasFileSystemService; } private void handlePeerSelectionChanged() { final PeerInfo info; ISelection selection = fPeerList.getSelection(); if (selection instanceof IStructuredSelection) { info = (PeerInfo) ((IStructuredSelection) selection).getFirstElement(); } else { info = null; } fSelectedPeer = info; fPeerHasFileSystemService = false; fPeerHasProcessesService = false; if (info != null) { Boolean[] available = new TCFTask<Boolean[]>() { public void run() { final IChannel channel = info.peer.openChannel(); channel.addChannelListener(new IChannelListener() { boolean opened; public void congestionLevel(int level) { } public void onChannelClosed(final Throwable error) { if (!opened) { // TODO report error? done(new Boolean[] { false, false }); } } public void onChannelOpened() { opened = true; Boolean hasFileSystemService = channel.getRemoteService(IFileSystem.class) != null; Boolean hasProcessesService = channel.getRemoteService(IProcesses.class) != null; channel.close(); done(new Boolean[] { hasFileSystemService, hasProcessesService }); } }); } }.getE(); fPeerHasFileSystemService = available[0]; fPeerHasProcessesService = available[1]; } return; } private PeerInfo getSelectedPeer() { return fSelectedPeer; } private String getSelectedPeerId() { PeerInfo info = getSelectedPeer(); if (info != null) { return info.id; } return null; } private IPath makeRelativeToWSRootLocation(IPath exePath, String remoteWsRoot, IPath wsRoot) { if (remoteWsRoot.length() != 0) { // use remoteWSRoot instead of Workspace Root if (wsRoot.isPrefixOf(exePath)) { return new Path(remoteWsRoot).append(exePath .removeFirstSegments(wsRoot.segmentCount()).setDevice( null)); } } return exePath; } private String getRemoteWSRoot() { // TODO remoteWSRoot? return ""; //$NON-NLS-1$ } }