/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License 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.github.sdbg.debug.ui.internal.androidreverseforwards;
import com.github.sdbg.debug.core.SDBGReverseForwardsLaunchConfigWrapper;
import com.github.sdbg.debug.ui.internal.SDBGDebugUIPlugin;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
/**
* The main UI tab for performing reverse port forwards on Android.
*/
public class AndroidReverseForwardsMainTab extends AbstractLaunchConfigurationTab {
private static final int MAX_FORWARDS = 5; // for now; results in a simpler user interface (no list views, add/remove etc.
private Text deviceText;
private Text deviceCommandPortText;
private Text[] hostTexts = new Text[MAX_FORWARDS], portTexts = new Text[MAX_FORWARDS],
devicePortTexts = new Text[MAX_FORWARDS];
protected ModifyListener textModifyListener = new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
notifyPanelChanged();
}
};
public AndroidReverseForwardsMainTab() {
setMessage("Create a configuration to run port forwards on Android devices");
}
@Override
public void createControl(Composite parent) {
final Composite composite = new Composite(parent, SWT.NONE);
GridLayoutFactory.swtDefaults().spacing(1, 3).applyTo(composite);
Group group = new Group(composite, SWT.NONE);
group.setText("Connection parameters");
GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
GridLayoutFactory.fillDefaults().numColumns(5).margins(12, 6).applyTo(group);
Label label = new Label(group, SWT.NONE);
label.setText("Device:");
deviceText = new Text(group, SWT.SINGLE | SWT.BORDER);
deviceText.addModifyListener(textModifyListener);
GridDataFactory.fillDefaults().grab(true, false).applyTo(deviceText);
label = new Label(group, SWT.NONE);
label = new Label(group, SWT.NONE);
label.setText("Command port:");
deviceCommandPortText = new Text(group, SWT.SINGLE | SWT.BORDER);
deviceCommandPortText.addModifyListener(textModifyListener);
GridDataFactory.swtDefaults().hint(40, -1).applyTo(deviceCommandPortText);
Group pfGroup = new Group(composite, SWT.NONE);
pfGroup.setText("Forwarding rules");
GridDataFactory.fillDefaults().grab(true, false).applyTo(pfGroup);
GridLayoutFactory.fillDefaults().numColumns(8).margins(12, 6).applyTo(pfGroup);
label = new Label(pfGroup, SWT.NONE);
Composite columnLabel = new Composite(pfGroup, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(1).applyTo(columnLabel);
GridDataFactory.fillDefaults().span(3, 1).grab(true, false).applyTo(columnLabel);
label = new Label(columnLabel, SWT.NONE);
label.setText("Android Device");
label = new Label(columnLabel, SWT.HORIZONTAL | SWT.SEPARATOR);
GridDataFactory.fillDefaults().grab(true, false).applyTo(label);
label = new Label(pfGroup, SWT.NONE);
columnLabel = new Composite(pfGroup, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(1).applyTo(columnLabel);
GridDataFactory.fillDefaults().span(3, 1).grab(true, false).applyTo(columnLabel);
label = new Label(columnLabel, SWT.NONE);
label.setText("Website");
label = new Label(columnLabel, SWT.HORIZONTAL | SWT.SEPARATOR);
GridDataFactory.fillDefaults().grab(true, false).applyTo(label);
for (int i = 0; i < MAX_FORWARDS; i++) {
label = new Label(pfGroup, SWT.NONE);
label.setText((i + 1) + ": ");
Text deviceHostText = new Text(pfGroup, SWT.SINGLE | SWT.BORDER);
deviceHostText.setEnabled(false);
deviceHostText.setText("localhost");
GridDataFactory.fillDefaults().grab(true, false).applyTo(deviceHostText);
label = new Label(pfGroup, SWT.NONE);
label.setText(":");
devicePortTexts[i] = new Text(pfGroup, SWT.SINGLE | SWT.BORDER);
devicePortTexts[i].addModifyListener(textModifyListener);
GridDataFactory.swtDefaults().hint(40, -1).applyTo(devicePortTexts[i]);
label = new Label(pfGroup, SWT.NONE);
label.setText("->");
GridDataFactory.swtDefaults().hint(20, -1).applyTo(label);
hostTexts[i] = new Text(pfGroup, SWT.SINGLE | SWT.BORDER);
hostTexts[i].addModifyListener(textModifyListener);
GridDataFactory.fillDefaults().grab(true, false).applyTo(hostTexts[i]);
label = new Label(pfGroup, SWT.NONE);
label.setText(":");
portTexts[i] = new Text(pfGroup, SWT.SINGLE | SWT.BORDER);
portTexts[i].addModifyListener(textModifyListener);
GridDataFactory.swtDefaults().hint(40, -1).applyTo(portTexts[i]);
}
final Label instructionsLabel = new Label(composite, SWT.WRAP);
instructionsLabel.setText("Make sure that \"USB debugging\" is enabled on your Android device. Then connect it to your PC via USB.\n\n"
+ "Use this feature to expose to the mobile browser development websites running on your PC or LAN (e.g. http://localhost:8080/<my-j2ee-app>).\n\n"
+ "This method may not work for public websites that inspect the HTTP Host header (e.g. http://gwtproject.org).");
GridDataFactory.fillDefaults().grab(true, false).hint(400, SWT.DEFAULT).applyTo(
instructionsLabel);
setControl(composite);
}
@Override
public String getErrorMessage() {
if (deviceCommandPortText.getText().trim().length() == 0) {
return "Enter device command port";
} else {
try {
int commandPort = Integer.parseInt(deviceCommandPortText.getText().trim());
if (commandPort < 0 || commandPort > 65535) {
return "Command port out of range (0 - 65536)";
}
} catch (Exception e) {
return "Invalid command port: " + e.getMessage();
}
}
String message = null;
for (int i = 0; i < MAX_FORWARDS; i++) {
String host = hostTexts[i].getText().trim();
String portStr = portTexts[i].getText().trim();
String devicePortStr = devicePortTexts[i].getText().trim();
if (host.length() > 0 || portStr.length() > 0 || devicePortStr.length() > 0) {
if (host.length() == 0) {
message = "Enter host";
} else if (portStr.length() == 0) {
message = "Enter port";
} else if (devicePortStr.length() == 0) {
message = "Enter device port";
} else {
try {
int port = Integer.parseInt(portStr);
if (port < 0 || port > 65535) {
message = "Port out of range (0 - 65536)";
}
} catch (Exception e) {
message = "Invalid port: " + e.getMessage();
}
if (message == null) {
try {
int devicePort = Integer.parseInt(devicePortStr);
if (devicePort < 0 || devicePort > 65535) {
message = "Device port out of range (0 - 65536)";
}
} catch (Exception e) {
message = "Invalid device port: " + e.getMessage();
}
}
}
if (message != null) {
message = "Rule " + (i + 1) + ": " + message;
break;
}
}
}
return message;
}
@Override
public Image getImage() {
return SDBGDebugUIPlugin.getImage("chrome_conn.png");
}
@Override
public String getName() {
return "Main";
}
@Override
public void initializeFrom(ILaunchConfiguration configuration) {
SDBGReverseForwardsLaunchConfigWrapper launchConfig = new SDBGReverseForwardsLaunchConfigWrapper(
configuration);
deviceText.setText(launchConfig.getDevice());
deviceCommandPortText.setText(Integer.toString(launchConfig.getDeviceCommandPort()));
List<String> rules = launchConfig.getReverseForwards();
for (int i = 0; i < MAX_FORWARDS; i++) {
if (i < rules.size()) {
String rule = rules.get(i);
hostTexts[i].setText(SDBGReverseForwardsLaunchConfigWrapper.getReverseForwardHost(rule));
portTexts[i].setText(Integer.toString(SDBGReverseForwardsLaunchConfigWrapper.getReverseForwardPort(rule)));
devicePortTexts[i].setText(Integer.toString(SDBGReverseForwardsLaunchConfigWrapper.getReverseForwardDevicePort(rule)));
} else {
hostTexts[i].setText("");
portTexts[i].setText("");
devicePortTexts[i].setText("");
}
}
}
@Override
public boolean isValid(ILaunchConfiguration launchConfig) {
return getErrorMessage() == null;
}
@Override
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
SDBGReverseForwardsLaunchConfigWrapper launchConfig = new SDBGReverseForwardsLaunchConfigWrapper(
configuration);
launchConfig.setDevice(deviceText.getText().trim());
int commandPort;
try {
commandPort = Integer.parseInt(deviceCommandPortText.getText().trim());
} catch (Exception e) {
commandPort = -1;
}
launchConfig.setDeviceCommandPort(commandPort);
List<String> rules = new ArrayList<String>();
for (int i = 0; i < MAX_FORWARDS; i++) {
String host = hostTexts[i].getText().trim();
String portStr = portTexts[i].getText().trim();
String devicePortStr = devicePortTexts[i].getText().trim();
if (host.length() > 0 || portStr.length() > 0 || devicePortStr.length() > 0) {
int port;
try {
port = Integer.parseInt(portStr);
} catch (Exception e) {
port = -1;
}
int devicePort;
try {
devicePort = Integer.parseInt(devicePortStr);
} catch (Exception e) {
devicePort = -1;
}
rules.add(SDBGReverseForwardsLaunchConfigWrapper.getReverseForward(host, port, devicePort));
}
}
launchConfig.setReverseForwards(rules);
}
@Override
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
SDBGReverseForwardsLaunchConfigWrapper launchConfig = new SDBGReverseForwardsLaunchConfigWrapper(
configuration);
launchConfig.setDevice("");
launchConfig.setDeviceCommandPort(6565);
launchConfig.setReverseForwardsStr("");
}
protected void notifyPanelChanged() {
setDirty(true);
updateLaunchConfigurationDialog();
}
}