/******************************************************************************* * Copyright (c) 2009 IBM Corporation 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: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.server.ui; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.window.Window; import org.eclipse.php.internal.debug.core.IPHPDebugConstants; import org.eclipse.php.internal.debug.core.PHPDebugPlugin; import org.eclipse.php.internal.debug.core.preferences.PHPProjectPreferences; import org.eclipse.php.internal.debug.ui.Logger; import org.eclipse.php.internal.debug.ui.launching.LaunchUtilities; import org.eclipse.php.internal.server.PHPServerUIMessages; import org.eclipse.php.internal.server.core.Server; import org.eclipse.php.internal.server.core.manager.ServersManager; import org.eclipse.php.internal.ui.IPHPHelpContextIds; import org.eclipse.php.internal.ui.preferences.ScrolledCompositeImpl; import org.eclipse.php.internal.ui.wizards.WizardModel; import org.eclipse.swt.SWT; import org.eclipse.swt.accessibility.AccessibleAdapter; import org.eclipse.swt.accessibility.AccessibleEvent; 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.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.*; import org.eclipse.ui.PlatformUI; public class ServerLaunchConfigurationTab extends AbstractLaunchConfigurationTab { protected IFile selectedFile = null; protected Text fFile; protected Label fURLLabel; protected Text fURLHost; protected Text fURLPath; protected Button projectButton; protected Button fileButton; protected Button publish; protected Button createNewServer; protected Button configureServers; protected Button autoGeneratedURL; protected String[] serverTypeIds; protected Combo serverCombo; protected Server server; protected boolean serverCanPublish = false; // list of servers that are in combo protected List<Server> servers; protected boolean init = true; // flag to be used to decide whether to enable combo in launch config dialog // after the user requests a launch, they cannot change it private static final String READ_ONLY = "read-only"; //$NON-NLS-1$ // flag to be used to decide whether to enable all components related // directly to the server attributes (file, URL, server combo, new server // button) private static final String SERVER_ENABLED = "serverEnabled"; //$NON-NLS-1$ /** * Indicates that the URL field is auto-generated according to the user * Server and resource selections. */ public static final String AUTO_GENERATED_URL = "auto_generated_url"; //$NON-NLS-1$ protected WidgetListener fListener = new WidgetListener(); private boolean saveWorkingCopy; private String basePath; /** * Create a new server launch configuration tab. */ public ServerLaunchConfigurationTab() { } /** * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(Composite) */ @Override public void createControl(Composite parent) { ScrolledCompositeImpl scrolledComposite = new ScrolledCompositeImpl(parent, SWT.V_SCROLL); Composite composite = new Composite(scrolledComposite, SWT.NONE); composite.setLayout(new GridLayout(1, false)); createServerControl(composite); createFileComponent(composite); createURLControl(composite); createExtensionControls(composite); Dialog.applyDialogFont(composite); scrolledComposite.setContent(composite); Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT); scrolledComposite.setMinSize(size.x, size.y); PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IPHPHelpContextIds.DEBUGGING_A_PHP_WEB_PAGE); setControl(scrolledComposite); } public void createExtensionControls(Composite composite) { return; } public void createURLControl(Composite composite) { Group group = new Group(composite, SWT.NONE); String projectLabel = PHPServerUIMessages.getString("ServerTab.url"); //$NON-NLS-1$ group.setText(projectLabel); group.setLayout(new GridLayout(2, false)); group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); autoGeneratedURL = new Button(group, SWT.CHECK); autoGeneratedURL.setText(PHPServerUIMessages.getString("ServerTab.autoGenerate")); //$NON-NLS-1$ autoGeneratedURL.setSelection(true); autoGeneratedURL.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1)); autoGeneratedURL.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { initializeURLControl(); updateLaunchConfigurationDialog(); } }); fURLLabel = new Label(group, SWT.NONE); fURLLabel.setText(PHPServerUIMessages.getString("ServerTab.urlLabel")); //$NON-NLS-1$ GridData gridData = new GridData(); gridData.horizontalIndent = 20; gridData.horizontalSpan = 1; fURLLabel.setLayoutData(gridData); Composite urlComposite = new Composite(group, SWT.NONE); urlComposite.setLayout(new GridLayout(2, false)); urlComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fURLHost = new Text(urlComposite, SWT.SINGLE | SWT.BORDER); fURLHost.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fURLHost.setEnabled(false); fURLPath = new Text(urlComposite, SWT.SINGLE | SWT.BORDER); fURLPath.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fURLPath.addModifyListener(e -> updateLaunchConfigurationDialog()); } protected void createServerSelectionControl(Composite parent) { Group group = new Group(parent, SWT.NONE); group.setText(PHPServerUIMessages.getString("ServerTab.server")); //$NON-NLS-1$ GridLayout ly = new GridLayout(1, false); ly.marginHeight = 0; ly.marginWidth = 0; group.setLayout(ly); group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Composite phpServerComp = new Composite(group, SWT.NONE); phpServerComp.setLayout(new GridLayout(4, false)); phpServerComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); phpServerComp.setFont(parent.getFont()); Label label = new Label(phpServerComp, SWT.WRAP); GridData data = new GridData(GridData.BEGINNING); data.widthHint = 100; label.setLayoutData(data); label.setFont(parent.getFont()); label.setText(PHPServerUIMessages.getString("ServerLaunchConfigurationTab.0")); //$NON-NLS-1$ serverCombo = new Combo(phpServerComp, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); serverCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); serverCombo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { handleServerSelection(); } }); createNewServer = createPushButton(phpServerComp, PHPServerUIMessages.getString("ServerTab.new"), null); //$NON-NLS-1$ createNewServer.addSelectionListener(fListener); configureServers = createPushButton(phpServerComp, PHPServerUIMessages.getString("ServerTab.configure"), null); //$NON-NLS-1$ configureServers.addSelectionListener(fListener); servers = new ArrayList<>(); populateServerList(servers); Collections.sort(servers, (o1, o2) -> o1.getName().compareTo(o2.getName())); // initialize the servers list if (!servers.isEmpty()) { for (int i = 0; i < servers.size(); i++) { Server svr = servers.get(i); serverCombo.add(svr.getName()); } } // select first item in list if (serverCombo.getItemCount() > 0) { serverCombo.select(0); } serverCombo.forceFocus(); } protected void populateServerList(List<Server> serverList) { Server[] servers = ServersManager.getServers(); if (serverList == null) serverList = new ArrayList<>(); if (servers != null) { int size = servers.length; for (int i = 0; i < size; i++) { serverList.add(servers[i]); } } } public void createServerControl(Composite parent) { createServerSelectionControl(parent); handleServerSelection(); } protected void createFileComponent(Composite parent) { Group group = new Group(parent, SWT.NONE); String projectLabel = PHPServerUIMessages.getString("ServerTab.file_project"); //$NON-NLS-1$ group.setText(projectLabel); group.setLayout(new GridLayout(3, false)); group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); fFile = new Text(group, SWT.SINGLE | SWT.BORDER); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; fFile.setLayoutData(gd); fFile.addModifyListener(fListener); fileButton = createPushButton(group, PHPServerUIMessages.getString("ServerTab.browse"), null); //$NON-NLS-1$ gd = (GridData) fileButton.getLayoutData(); gd.horizontalSpan = 1; fileButton.addSelectionListener(fListener); handleServerSelection(); } public String[] getRequiredNatures() { return null; } protected void handleServerButtonSelected() { final Server newServer = getServerFromWizard(); if (newServer != null) { Display.getDefault().asyncExec(() -> { servers.add(newServer); serverCombo.add(newServer.getName()); serverCombo.select(serverCombo.indexOf(newServer.getName())); handleServerSelection(); }); } } protected void handleConfigureButtonSelected() { int selectionIndex = serverCombo.getSelectionIndex(); Server server = servers.get(selectionIndex); String serverName = server.getName(); NullProgressMonitor monitor = new NullProgressMonitor(); if (ServerEditWizardRunner.runWizard(server) == Window.CANCEL) { monitor.setCanceled(true); return; } ServersManager.save(); String newName = server.getName(); if (!newName.equals(serverName)) { serverCombo.remove(selectionIndex); serverCombo.add(newName, selectionIndex); serverCombo.select(selectionIndex); } saveWorkingCopy = true; handleServerSelection(); } public String[] getFileExtensions() { return null; } private IResource getFileFromDialog(IProject project) { return LaunchUtilities.getFileFromDialog(project, getShell(), getFileExtensions(), getRequiredNatures(), false); } protected void handleFileButtonSelected() { IResource file = null; file = getFileFromDialog(null); if (file == null) return; String fName = file.getFullPath().toString(); fFile.setText(fName); if (autoGeneratedURL.getSelection()) { updateURLComponents(computeURL(formatFileName(fName))); } } private String getBasePath(IProject project) { return initializeBasePath(project); } protected void updateURLComponents(String urlStr) { try { URL url = new URL(urlStr); String port = url.getPort() == -1 ? "" : ":" + url.getPort(); //$NON-NLS-1$ //$NON-NLS-2$ fURLHost.setText(url.getProtocol() + "://" + url.getHost() + port + "/"); //$NON-NLS-1$ //$NON-NLS-2$ if (url.getQuery() != null) { fURLPath.setText(url.getPath() + "?" + url.getQuery()); //$NON-NLS-1$ } else { fURLPath.setText(url.getPath()); } } catch (MalformedURLException e) { Logger.logException(e); } } protected IProject getProject(String name) { IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); IProject[] projects = workspaceRoot.getProjects(); if (projects == null || projects.length == 0) return null; for (IProject project : projects) { if (project.getName().equals(name)) return project; } return null; } /** * Called when a server is selected. This method should not be called * directly. */ protected void handleServerSelection() { int numEntries = serverCombo.getItemCount(); int index = serverCombo.getSelectionIndex(); if (!servers.isEmpty()) { Object obj = servers.get(serverCombo.getSelectionIndex()); if (obj != null && obj instanceof Server) { server = servers.get(serverCombo.getSelectionIndex()); initializeURLControl(); } } if (server == null && (index + 1) != numEntries) setErrorMessage(PHPServerUIMessages.getString("ServerTab.noSelectedServerError")); //$NON-NLS-1$ else { setErrorMessage(null); } updateLaunchConfigurationDialog(); } /** * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(ILaunchConfigurationWorkingCopy) */ @Override public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { setErrorMessage(null); try { selectDefaultServer(configuration); } catch (CoreException e) { Logger.logException(e); } } /** * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(ILaunchConfiguration) */ @Override public void initializeFrom(ILaunchConfiguration configuration) { serverCombo.setEnabled(true); // remove error message that other instances may have set setErrorMessage(null); try { String fileName = configuration.getAttribute(Server.FILE_NAME, ""); //$NON-NLS-1$ String url = configuration.getAttribute(Server.BASE_URL, ""); //$NON-NLS-1$ boolean isAutoGeneratedURL = configuration.getAttribute(AUTO_GENERATED_URL, true); initializeServerControl(configuration); if (isAutoGeneratedURL) { autoGeneratedURL.setSelection(true); String computedURL = computeURL(formatFileName(fileName)); fURLLabel.setEnabled(false); updateURLComponents(computedURL); fURLPath.setEnabled(false); } else { autoGeneratedURL.setSelection(false); fURLLabel.setEnabled(true); updateURLComponents(url); fURLPath.setEnabled(true); } fFile.setText(fileName); updateFileEnabled(configuration); updateURLEnabled(configuration); } catch (CoreException e) { // ignore } initializeExtensionControls(configuration); isValid(configuration); } private void updateURLEnabled(ILaunchConfiguration configuration) throws CoreException { boolean enabled = configuration.getAttribute(SERVER_ENABLED, true); fURLLabel.getParent().setVisible(enabled); if (enabled) { fURLPath.setEnabled(!autoGeneratedURL.getSelection()); } } private void updateFileEnabled(ILaunchConfiguration configuration) throws CoreException { boolean enabled = configuration.getAttribute(SERVER_ENABLED, true); fFile.getParent().setVisible(enabled); } private String initializeBasePath(IProject project) { if (project == null) return null; return PHPProjectPreferences.getDefaultBasePath(project); } protected void initializeExtensionControls(ILaunchConfiguration configuration) { return; } /** * Constructs the URL string according to the given context root and the * file name. * * @param fileName * @return */ protected String computeURL(String fileName) { if (server == null) { return ""; //$NON-NLS-1$ } String urlString = server.getBaseURL(); if (urlString.isEmpty()) { urlString = "http://localhost"; //$NON-NLS-1$ } StringBuilder url = new StringBuilder(urlString); if (!fileName.isEmpty()) { url.append(fileName); } return url.toString(); } private String formatFileName(String fileName) { String formatFile; IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IResource resource = root.findMember(fileName); if (resource == null) { return fileName; } basePath = getBasePath(resource.getProject()); if (basePath == null && resource.getProject() != null) basePath = resource.getProject().getName(); else if (basePath == null && resource.getProject() == null) { basePath = ""; //$NON-NLS-1$ } int type = resource.getType(); if (type == IResource.FILE || type == IResource.FOLDER) { formatFile = basePath + "/" //$NON-NLS-1$ + resource.getFullPath().removeFirstSegments(1).toString(); } else { formatFile = basePath + "/"; //$NON-NLS-1$ } if (!formatFile.startsWith("/")) { //$NON-NLS-1$ formatFile = basePath + "/" + formatFile; //$NON-NLS-1$ } return formatFile; } protected void initializeURLControl() { if (fFile == null || fURLPath == null || fURLHost == null) { return; } String file; if (autoGeneratedURL.getSelection()) { file = formatFileName(fFile.getText()); } else { file = fURLPath.getText(); } updateURLComponents(computeURL(file)); } protected void initializeServerControl(ILaunchConfiguration configuration) { try { String serverName = configuration.getAttribute(Server.NAME, ""); //$NON-NLS-1$ if (serverName != null && !serverName.equals("")) { //$NON-NLS-1$ server = ServersManager.getServer(serverName); if (server == null) { // server no longer exists setErrorMessage(PHPServerUIMessages.getString("ServerTab.invalidServerError")); //$NON-NLS-1$ selectDefaultServer(configuration); } else { serverCombo.setText(server.getName()); } } else { selectDefaultServer(configuration); } // flag should only be set if launch has been attempted on the // config if (configuration.getAttribute(READ_ONLY, false)) { serverCombo.setEnabled(false); } boolean enabled = configuration.getAttribute(SERVER_ENABLED, true); serverCombo.setEnabled(enabled); createNewServer.setEnabled(enabled); } catch (Exception e) { } } /* * Select the default server. */ private void selectDefaultServer(ILaunchConfiguration configuration) throws CoreException { if (serverCombo != null && serverCombo.getItemCount() > 0) { // Select the default server String projectName = configuration.getAttribute(IPHPDebugConstants.PHP_Project, (String) null); IProject project = null; if (projectName != null) { project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); } Server defaultServer = ServersManager.getDefaultServer(project); int nameIndex = serverCombo.indexOf(defaultServer.getName()); if (nameIndex > -1) { serverCombo.select(nameIndex); } else { serverCombo.select(0); } server = ServersManager.getServer(serverCombo.getText()); } } /** * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(ILaunchConfigurationWorkingCopy) */ @Override public void performApply(ILaunchConfigurationWorkingCopy configuration) { if (server != null) { configuration.setAttribute(Server.NAME, server.getName()); } else { configuration.setAttribute(Server.NAME, (String) null); } String fileName = fFile.getText(); String urlPath = fURLPath.getText().replace('\\', '/'); if (urlPath.startsWith("/")) { //$NON-NLS-1$ urlPath = urlPath.substring(1); } String url = fURLHost.getText() + urlPath; configuration.setAttribute(Server.FILE_NAME, fileName); configuration.setAttribute(Server.BASE_URL, url); configuration.setAttribute(AUTO_GENERATED_URL, autoGeneratedURL.getSelection()); try { updateURLEnabled(configuration); } catch (CoreException e) { PHPDebugPlugin.log(e); } applyExtension(configuration); if (saveWorkingCopy) { try { configuration.doSave(); } catch (CoreException e) { } saveWorkingCopy = false; } } protected void applyExtension(ILaunchConfigurationWorkingCopy configuration) { return; } /** * @see org.eclipse.debug.ui.ILaunchConfigurationTab#isValid(ILaunchConfiguration) */ public boolean isValid(ILaunchConfiguration launchConfig) { setMessage(null); setErrorMessage(null); // TODO - Note that this method of removing invalid launches is still // buggy // In order to fix it completely, we might have to perform similar // checks when removing or renaming a server from // the PHP Servers preferences page. try { String serverName = launchConfig.getAttribute(Server.NAME, ""); //$NON-NLS-1$ if (!serverName.isEmpty()) { Server server = ServersManager.getServer(serverName); if (server == null) { deleteLaunchConfiguration(launchConfig); ILaunchConfiguration[] allConfigurations = DebugPlugin.getDefault().getLaunchManager() .getLaunchConfigurations(); for (ILaunchConfiguration element : allConfigurations) { launchConfig = element; serverName = launchConfig.getAttribute(Server.NAME, ""); //$NON-NLS-1$ if (!serverName.equals("") && ServersManager.getServer(serverName) == null) { //$NON-NLS-1$ // The server was removed, so remove this launch // configuration! deleteLaunchConfiguration(launchConfig); } } return false; } else { if (ServersManager.isNoneServer(server)) { setErrorMessage(PHPServerUIMessages.getString("ServerTab.noSelectedServerError")); //$NON-NLS-1$ return false; } } } String fileName = launchConfig.getAttribute(Server.FILE_NAME, ""); //$NON-NLS-1$ IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(fileName); if (!(resource instanceof IFile)) { setErrorMessage(PHPServerUIMessages.getString("ServerTab.file_project_doesNotExist")); //$NON-NLS-1$ return false; } } catch (CoreException e) { // ignore } return isValidExtension(launchConfig); } private void deleteLaunchConfiguration(final ILaunchConfiguration launchConfig) throws CoreException { Display.getDefault().asyncExec(() -> { ILaunchConfiguration config = launchConfig; try { if (config instanceof ILaunchConfigurationWorkingCopy) { config = ((ILaunchConfigurationWorkingCopy) config).getOriginal(); } if (config != null) { config.delete(); } } catch (CoreException ce) { // Ignore } }); } protected boolean isValidExtension(ILaunchConfiguration launchConfig) { return true; } /** * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getImage() */ @Override public Image getImage() { return ServersPluginImages.get(ServersPluginImages.IMG_SERVER); } /** * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() */ public String getName() { return PHPServerUIMessages.getString("ServerTab.server"); //$NON-NLS-1$ } /* * Fix for Bug 60163 Accessibility: New Builder Dialog missing object info * for textInput controls */ public void addControlAccessibleListener(Control control, String controlName) { // strip mnemonic (&) String[] strs = controlName.split("&"); //$NON-NLS-1$ StringBuilder stripped = new StringBuilder(); for (String element : strs) { stripped.append(element); } control.getAccessible().addAccessibleListener(new ControlAccessibleListener(stripped.toString())); } private class ControlAccessibleListener extends AccessibleAdapter { private String controlName; ControlAccessibleListener(String name) { controlName = name; } @Override public void getName(AccessibleEvent e) { e.result = controlName; } } protected Server getServerFromWizard() { Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); NullProgressMonitor monitor = new NullProgressMonitor(); ServerWizard wizard = new ServerWizard(); ClosableWizardDialog dialog = new ClosableWizardDialog(shell, wizard); if (dialog.open() == Window.CANCEL) { monitor.setCanceled(true); return null; } Server theServer = (Server) wizard.getRootFragment().getWizardModel().getObject(WizardModel.SERVER); if (theServer != null) { ServersManager.addServer(theServer); ServersManager.save(); } return theServer; } protected class WidgetListener extends SelectionAdapter implements ModifyListener { @Override public void modifyText(ModifyEvent e) { updateLaunchConfigurationDialog(); initializeURLControl(); } @Override public void widgetSelected(SelectionEvent e) { setDirty(true); Object source = e.getSource(); if (source == fileButton) { handleFileButtonSelected(); } else if (source == createNewServer) { handleServerButtonSelected(); } else if (source == configureServers) { handleConfigureButtonSelected(); } } } }