1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.monitor.ddms; 18 19 import com.android.ddmlib.IDevice; 20 21 import org.eclipse.swt.SWT; 22 import org.eclipse.swt.events.ModifyEvent; 23 import org.eclipse.swt.events.ModifyListener; 24 import org.eclipse.swt.events.SelectionAdapter; 25 import org.eclipse.swt.events.SelectionEvent; 26 import org.eclipse.swt.graphics.Rectangle; 27 import org.eclipse.swt.layout.GridData; 28 import org.eclipse.swt.layout.GridLayout; 29 import org.eclipse.swt.widgets.Button; 30 import org.eclipse.swt.widgets.Composite; 31 import org.eclipse.swt.widgets.Dialog; 32 import org.eclipse.swt.widgets.Display; 33 import org.eclipse.swt.widgets.Event; 34 import org.eclipse.swt.widgets.Label; 35 import org.eclipse.swt.widgets.Listener; 36 import org.eclipse.swt.widgets.Shell; 37 import org.eclipse.swt.widgets.Text; 38 39 import java.util.ArrayList; 40 41 /** 42 * Small dialog box to edit a static port number. 43 */ 44 public class StaticPortEditDialog extends Dialog { 45 46 private static final int DLG_WIDTH = 400; 47 private static final int DLG_HEIGHT = 200; 48 49 private Shell mParent; 50 51 private Shell mShell; 52 53 private boolean mOk = false; 54 55 private String mAppName; 56 57 private String mPortNumber; 58 59 private Button mOkButton; 60 61 private Label mWarning; 62 63 /** List of ports already in use */ 64 private ArrayList<Integer> mPorts; 65 66 /** This is the port being edited. */ 67 private int mEditPort = -1; 68 private String mDeviceSn; 69 70 /** 71 * Creates a dialog with empty fields. 72 * @param parent The parent Shell 73 * @param ports The list of already used port numbers. 74 */ 75 public StaticPortEditDialog(Shell parent, ArrayList<Integer> ports) { 76 super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL); 77 mPorts = ports; 78 mDeviceSn = IDevice.FIRST_EMULATOR_SN; 79 } 80 81 /** 82 * Creates a dialog with predefined values. 83 * @param shell The parent shell 84 * @param ports The list of already used port numbers. 85 * @param oldDeviceSN the device serial number to display 86 * @param oldAppName The application name to display 87 * @param oldPortNumber The port number to display 88 */ 89 public StaticPortEditDialog(Shell shell, ArrayList<Integer> ports, 90 String oldDeviceSN, String oldAppName, String oldPortNumber) { 91 this(shell, ports); 92 93 mDeviceSn = oldDeviceSN; 94 mAppName = oldAppName; 95 mPortNumber = oldPortNumber; 96 mEditPort = Integer.valueOf(mPortNumber); 97 } 98 99 /** 100 * Opens the dialog. The method will return when the user closes the dialog 101 * somehow. 102 * 103 * @return true if ok was pressed, false if cancelled. 104 */ 105 public boolean open() { 106 createUI(); 107 108 if (mParent == null || mShell == null) { 109 return false; 110 } 111 112 mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT); 113 Rectangle r = mParent.getBounds(); 114 // get the center new top left. 115 int cx = r.x + r.width/2; 116 int x = cx - DLG_WIDTH / 2; 117 int cy = r.y + r.height/2; 118 int y = cy - DLG_HEIGHT / 2; 119 mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT); 120 121 mShell.open(); 122 123 Display display = mParent.getDisplay(); 124 while (!mShell.isDisposed()) { 125 if (!display.readAndDispatch()) 126 display.sleep(); 127 } 128 129 return mOk; 130 } 131 132 public String getDeviceSN() { 133 return mDeviceSn; 134 } 135 136 public String getAppName() { 137 return mAppName; 138 } 139 140 public int getPortNumber() { 141 return Integer.valueOf(mPortNumber); 142 } 143 144 private void createUI() { 145 mParent = getParent(); 146 mShell = new Shell(mParent, getStyle()); 147 mShell.setText("Static Port"); 148 149 mShell.setLayout(new GridLayout(1, false)); 150 151 mShell.addListener(SWT.Close, new Listener() { 152 @Override 153 public void handleEvent(Event event) { 154 } 155 }); 156 157 // center part with the edit field 158 Composite main = new Composite(mShell, SWT.NONE); 159 main.setLayoutData(new GridData(GridData.FILL_BOTH)); 160 main.setLayout(new GridLayout(2, false)); 161 162 Label l0 = new Label(main, SWT.NONE); 163 l0.setText("Device Name:"); 164 165 final Text deviceSNText = new Text(main, SWT.SINGLE | SWT.BORDER); 166 deviceSNText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 167 if (mDeviceSn != null) { 168 deviceSNText.setText(mDeviceSn); 169 } 170 deviceSNText.addModifyListener(new ModifyListener() { 171 @Override 172 public void modifyText(ModifyEvent e) { 173 mDeviceSn = deviceSNText.getText().trim(); 174 validate(); 175 } 176 }); 177 178 Label l = new Label(main, SWT.NONE); 179 l.setText("Application Name:"); 180 181 final Text appNameText = new Text(main, SWT.SINGLE | SWT.BORDER); 182 if (mAppName != null) { 183 appNameText.setText(mAppName); 184 } 185 appNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 186 appNameText.addModifyListener(new ModifyListener() { 187 @Override 188 public void modifyText(ModifyEvent e) { 189 mAppName = appNameText.getText().trim(); 190 validate(); 191 } 192 }); 193 194 Label l2 = new Label(main, SWT.NONE); 195 l2.setText("Debug Port:"); 196 197 final Text debugPortText = new Text(main, SWT.SINGLE | SWT.BORDER); 198 if (mPortNumber != null) { 199 debugPortText.setText(mPortNumber); 200 } 201 debugPortText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 202 debugPortText.addModifyListener(new ModifyListener() { 203 @Override 204 public void modifyText(ModifyEvent e) { 205 mPortNumber = debugPortText.getText().trim(); 206 validate(); 207 } 208 }); 209 210 // warning label 211 Composite warningComp = new Composite(mShell, SWT.NONE); 212 warningComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 213 warningComp.setLayout(new GridLayout(1, true)); 214 215 mWarning = new Label(warningComp, SWT.NONE); 216 mWarning.setText(""); 217 mWarning.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 218 219 // bottom part with the ok/cancel 220 Composite bottomComp = new Composite(mShell, SWT.NONE); 221 bottomComp 222 .setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); 223 bottomComp.setLayout(new GridLayout(2, true)); 224 225 mOkButton = new Button(bottomComp, SWT.NONE); 226 mOkButton.setText("OK"); 227 mOkButton.addSelectionListener(new SelectionAdapter() { 228 @Override 229 public void widgetSelected(SelectionEvent e) { 230 mOk = true; 231 mShell.close(); 232 } 233 }); 234 mOkButton.setEnabled(false); 235 mShell.setDefaultButton(mOkButton); 236 237 Button cancelButton = new Button(bottomComp, SWT.NONE); 238 cancelButton.setText("Cancel"); 239 cancelButton.addSelectionListener(new SelectionAdapter() { 240 @Override 241 public void widgetSelected(SelectionEvent e) { 242 mShell.close(); 243 } 244 }); 245 246 validate(); 247 } 248 249 /** 250 * Validates the content of the 2 text fields and enable/disable "ok", while 251 * setting up the warning/error message. 252 */ 253 private void validate() { 254 // first we reset the warning dialog. This allows us to latter 255 // display warnings. 256 mWarning.setText(""); //$NON-NLS-1$ 257 258 // check the device name field is not empty 259 if (mDeviceSn == null || mDeviceSn.length() == 0) { 260 mWarning.setText("Device name missing."); 261 mOkButton.setEnabled(false); 262 return; 263 } 264 265 // check the application name field is not empty 266 if (mAppName == null || mAppName.length() == 0) { 267 mWarning.setText("Application name missing."); 268 mOkButton.setEnabled(false); 269 return; 270 } 271 272 String packageError = "Application name must be a valid Java package name."; 273 274 // validate the package name as well. It must be a fully qualified 275 // java package. 276 String[] packageSegments = mAppName.split("\\."); //$NON-NLS-1$ 277 for (String p : packageSegments) { 278 if (p.matches("^[a-zA-Z][a-zA-Z0-9]*") == false) { //$NON-NLS-1$ 279 mWarning.setText(packageError); 280 mOkButton.setEnabled(false); 281 return; 282 } 283 284 // lets also display a warning if the package contains upper case 285 // letters. 286 if (p.matches("^[a-z][a-z0-9]*") == false) { //$NON-NLS-1$ 287 mWarning.setText("Lower case is recommended for Java packages."); 288 } 289 } 290 291 // the split will not detect the last char being a '.' 292 // so we test it manually 293 if (mAppName.charAt(mAppName.length()-1) == '.') { 294 mWarning.setText(packageError); 295 mOkButton.setEnabled(false); 296 return; 297 } 298 299 // now we test the package name field is not empty. 300 if (mPortNumber == null || mPortNumber.length() == 0) { 301 mWarning.setText("Port Number missing."); 302 mOkButton.setEnabled(false); 303 return; 304 } 305 306 // then we check it only contains digits. 307 if (mPortNumber.matches("[0-9]*") == false) { //$NON-NLS-1$ 308 mWarning.setText("Port Number invalid."); 309 mOkButton.setEnabled(false); 310 return; 311 } 312 313 // get the int from the port number to validate 314 long port = Long.valueOf(mPortNumber); 315 if (port >= 32767) { 316 mOkButton.setEnabled(false); 317 return; 318 } 319 320 // check if its in the list of already used ports 321 if (port != mEditPort) { 322 for (Integer i : mPorts) { 323 if (port == i.intValue()) { 324 mWarning.setText("Port already in use."); 325 mOkButton.setEnabled(false); 326 return; 327 } 328 } 329 } 330 331 // at this point there's not error, so we enable the ok button. 332 mOkButton.setEnabled(true); 333 } 334 } 335