1 16 package com.google.gwt.dev.shell; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.UnableToCompleteException; 20 import com.google.gwt.dev.util.Util; 21 22 import org.eclipse.swt.SWT; 23 import org.eclipse.swt.browser.Browser; 24 import org.eclipse.swt.browser.LocationEvent; 25 import org.eclipse.swt.browser.LocationListener; 26 import org.eclipse.swt.browser.OpenWindowListener; 27 import org.eclipse.swt.browser.StatusTextEvent; 28 import org.eclipse.swt.browser.StatusTextListener; 29 import org.eclipse.swt.browser.TitleEvent; 30 import org.eclipse.swt.browser.TitleListener; 31 import org.eclipse.swt.browser.WindowEvent; 32 import org.eclipse.swt.events.DisposeEvent; 33 import org.eclipse.swt.events.DisposeListener; 34 import org.eclipse.swt.events.FocusEvent; 35 import org.eclipse.swt.events.FocusListener; 36 import org.eclipse.swt.events.KeyEvent; 37 import org.eclipse.swt.events.KeyListener; 38 import org.eclipse.swt.events.SelectionAdapter; 39 import org.eclipse.swt.events.SelectionEvent; 40 import org.eclipse.swt.events.SelectionListener; 41 import org.eclipse.swt.graphics.Color; 42 import org.eclipse.swt.graphics.Cursor; 43 import org.eclipse.swt.layout.GridData; 44 import org.eclipse.swt.layout.GridLayout; 45 import org.eclipse.swt.program.Program; 46 import org.eclipse.swt.widgets.Button; 47 import org.eclipse.swt.widgets.Composite; 48 import org.eclipse.swt.widgets.Label; 49 import org.eclipse.swt.widgets.MessageBox; 50 import org.eclipse.swt.widgets.Shell; 51 import org.eclipse.swt.widgets.Text; 52 import org.eclipse.swt.widgets.ToolItem; 53 54 import java.io.File ; 55 import java.io.IOException ; 56 import java.util.HashMap ; 57 import java.util.HashSet ; 58 import java.util.Iterator ; 59 import java.util.Map ; 60 import java.util.Set ; 61 62 65 public abstract class BrowserWidget extends Composite { 66 67 private class Toolbar extends HeaderBarBase implements SelectionListener { 68 private final ToolItem backButton; 69 70 private final ToolItem forwardButton; 71 72 private final ToolItem openWebModeButton; 73 74 private final ToolItem refreshButton; 75 private final ToolItem stopButton; 76 77 public Toolbar(Composite parent) { 78 super(parent); 79 80 backButton = newItem("back.gif", " &Back ", "Go back one state"); 81 backButton.addSelectionListener(this); 82 83 forwardButton = newItem("forward.gif", "&Forward", "Go forward one state"); 84 forwardButton.addSelectionListener(this); 85 86 refreshButton = newItem("refresh.gif", " &Refresh ", "Reload the page"); 87 refreshButton.addSelectionListener(this); 88 89 stopButton = newItem("stop.gif", " &Stop ", "Stop loading the page"); 90 stopButton.addSelectionListener(this); 91 92 newSeparator(); 93 94 openWebModeButton = newItem("new-web-mode-window.gif", "&Compile/Browse", 95 "Compiles and opens the current URL in the system browser"); 96 openWebModeButton.addSelectionListener(this); 97 openWebModeButton.setEnabled(false); 98 } 99 100 public void widgetDefaultSelected(SelectionEvent e) { 101 } 102 103 public void widgetSelected(SelectionEvent evt) { 104 if (evt.widget == backButton) { 105 browser.back(); 106 } else if (evt.widget == forwardButton) { 107 browser.forward(); 108 } else if (evt.widget == refreshButton) { 109 112 browser.refresh(); 114 } else if (evt.widget == stopButton) { 115 browser.stop(); 116 } else if (evt.widget == openWebModeButton) { 117 Set keySet = new HashSet (); 119 for (Iterator iter = loadedModules.entrySet().iterator(); 120 iter.hasNext(); ) { 121 ModuleSpace module 122 = (ModuleSpace) ((Map.Entry ) iter.next()).getValue(); 123 keySet.add(module.getModuleName()); 124 } 125 String [] moduleNames = Util.toStringArray(keySet); 126 if (moduleNames.length == 0) { 127 openWebModeButton.setEnabled(false); 130 return; 131 } 132 try { 133 Cursor waitCursor = getDisplay().getSystemCursor(SWT.CURSOR_WAIT); 134 getShell().setCursor(waitCursor); 135 getHost().compile(moduleNames); 136 } catch (UnableToCompleteException e) { 137 MessageBox msgBox = new MessageBox(getShell(), SWT.OK 140 | SWT.ICON_ERROR); 141 msgBox.setText("Compilation Failed"); 142 msgBox.setMessage("Compilation failed. Please see the log in the development shell for details."); 143 msgBox.open(); 144 return; 145 } finally { 146 Cursor normalCursor = getDisplay().getSystemCursor(SWT.CURSOR_ARROW); 149 getShell().setCursor(normalCursor); 150 } 151 152 String locationText = location.getText(); 153 154 launchExternalBrowser(logger, locationText); 155 } 156 } 157 } 158 159 static void launchExternalBrowser(TreeLogger logger, String location) { 160 161 LowLevel.init(); 163 String browserCmd = LowLevel.getEnv("GWT_EXTERNAL_BROWSER"); 164 if (browserCmd != null) { 165 browserCmd += " " + location; 166 try { 167 Runtime.getRuntime().exec(browserCmd); 168 return; 169 } catch (IOException e) { 170 logger.log(TreeLogger.ERROR, 171 "Error launching GWT_EXTERNAL_BROWSER executable '" + browserCmd 172 + "'", e); 173 return; 174 } 175 } 176 177 browserCmd = System.getProperty("gwt.browser.default"); 179 if (browserCmd != null) { 180 browserCmd += " " + location; 181 try { 182 Runtime.getRuntime().exec(browserCmd); 183 return; 184 } catch (IOException e) { 185 logger.log(TreeLogger.ERROR, 186 "Error launching gwt.browser.default executable '" + browserCmd 187 + "'", e); 188 return; 189 } 190 } 191 192 Program browserProgram = Program.findProgram("html"); 194 if (browserProgram != null) { 195 if (browserProgram.execute(location)) { 196 return; 197 } else { 198 logger.log(TreeLogger.ERROR, "Error launching external HTML program '" 199 + browserProgram.getName() + "'", null); 200 return; 201 } 202 } 203 204 logger.log(TreeLogger.ERROR, 206 "Unable to find a default external web browser", null); 207 208 logger.log(TreeLogger.WARN, "Try setting the environment variable " 209 + "GWT_EXTERNAL_BROWSER to your web browser executable before " 210 + "launching the GWT shell", null); 211 } 212 213 protected Browser browser; 214 215 private Color bgColor = new Color(null, 239, 237, 216); 216 217 private Button goButton; 218 219 private final BrowserWidgetHost host; 220 221 private final Map loadedModules = new HashMap (); 222 223 private Text location; 224 225 private final TreeLogger logger; 226 227 private Label statusBar; 228 229 private Toolbar toolbar; 230 231 public BrowserWidget(Composite parent, BrowserWidgetHost host) { 232 super(parent, SWT.NONE); 233 234 this.host = host; 235 logger = this.host.getLogger(); 236 237 bgColor = new Color(null, 239, 237, 216); 238 239 toolbar = new Toolbar(this); 240 Composite secondBar = buildLocationBar(this); 241 242 browser = new Browser(this, SWT.NONE); 243 244 { 245 statusBar = new Label(this, SWT.BORDER | SWT.SHADOW_IN); 246 statusBar.setBackground(bgColor); 247 GridData gridData = new GridData(GridData.FILL_HORIZONTAL); 248 gridData.verticalAlignment = GridData.CENTER; 249 gridData.verticalIndent = 0; 250 gridData.horizontalIndent = 0; 251 statusBar.setLayoutData(gridData); 252 } 253 254 GridLayout layout = new GridLayout(); 255 layout.numColumns = 1; 256 layout.verticalSpacing = 1; 257 layout.marginWidth = 0; 258 layout.marginHeight = 0; 259 setLayout(layout); 260 261 toolbar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 262 secondBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 263 264 GridData data = new GridData(GridData.FILL_BOTH); 265 data.grabExcessVerticalSpace = true; 266 data.grabExcessHorizontalSpace = true; 267 browser.setLayoutData(data); 268 269 hookBrowserListeners(); 272 } 273 274 277 public Browser getBrowser() { 278 return browser; 279 } 280 281 public BrowserWidgetHost getHost() { 282 return host; 283 } 284 285 289 public void go(String target) { 290 String url = host.normalizeURL(target); 291 browser.setUrl(url); 292 } 293 294 public void onFirstShown() { 295 String baseUrl = host.normalizeURL("/"); 296 setLocationText(baseUrl); 297 location.setFocus(); 298 location.setSelection(baseUrl.length()); 299 location.addFocusListener(new FocusListener() { 300 public void focusGained(FocusEvent e) { 301 int length = location.getText().length(); 302 location.setSelection(length, length); 303 } 304 305 public void focusLost(FocusEvent e) { 306 } 307 }); 308 } 309 310 316 protected final void attachModuleSpace(ModuleSpace space) 317 throws UnableToCompleteException { 318 Object key = space.getKey(); 319 loadedModules.put(key, space); 320 321 logger.log(TreeLogger.SPAM, "Loading module " + space.getModuleName() 322 + " (id " + key.toString() + ")", null); 323 324 space.onLoad(logger); 327 328 toolbar.openWebModeButton.setEnabled(true); 331 } 332 333 339 protected void doUnload(Object key) { 340 if (key == null) { 341 for (Iterator iter = loadedModules.entrySet().iterator(); 344 iter.hasNext(); ) { 345 unloadModule((ModuleSpace) ((Map.Entry ) iter.next()).getValue()); 346 } 347 loadedModules.clear(); 348 } else { 350 ModuleSpace moduleSpace = (ModuleSpace) loadedModules.get(key); 351 if (moduleSpace == null) { 352 throw new HostedModeException("Can't find frame window for " + key); 353 } 354 unloadModule(moduleSpace); 355 loadedModules.remove(key); 356 } 357 if (loadedModules.isEmpty()) { 358 if (!toolbar.openWebModeButton.isDisposed()) { 359 toolbar.openWebModeButton.setEnabled(false); 362 } 363 } 364 } 365 366 371 protected void unloadModule(ModuleSpace moduleSpace) { 372 String moduleName = moduleSpace.getModuleName(); 373 Object key = moduleSpace.getKey(); 374 moduleSpace.dispose(); 375 logger.log(TreeLogger.SPAM, "Unloading module " + moduleName 376 + " (id " + key.toString() + ")", null); 377 } 378 379 private Composite buildLocationBar(Composite parent) { 380 Color white = new Color(null, 255, 255, 255); 381 382 Composite bar = new Composite(parent, SWT.BORDER); 383 bar.setBackground(white); 384 385 location = new Text(bar, SWT.FLAT); 386 387 goButton = new Button(bar, SWT.NONE); 388 goButton.setBackground(bgColor); 389 goButton.setText("Go"); 390 goButton.setImage(LowLevel.loadImage("go.gif")); 391 392 GridLayout layout = new GridLayout(); 393 layout.numColumns = 2; 394 layout.marginWidth = layout.marginHeight = 0; 395 layout.marginLeft = 2; 396 layout.verticalSpacing = layout.horizontalSpacing = 0; 397 bar.setLayout(layout); 398 399 GridData data = new GridData(GridData.FILL_HORIZONTAL); 400 data.grabExcessHorizontalSpace = true; 401 data.verticalAlignment = GridData.CENTER; 402 location.setLayoutData(data); 403 404 return bar; 405 } 406 407 410 private void hookBrowserListeners() { 411 412 this.addDisposeListener(new DisposeListener() { 413 public void widgetDisposed(DisposeEvent e) { 414 bgColor.dispose(); 415 } 416 }); 417 418 goButton.addSelectionListener(new SelectionAdapter() { 419 public void widgetSelected(SelectionEvent e) { 420 go(location.getText()); 421 } 422 }); 423 424 location.addKeyListener(new KeyListener() { 427 public void keyPressed(KeyEvent e) { 428 if (e.character == '\r') { 429 go(location.getText()); 430 } 431 } 432 433 public void keyReleased(KeyEvent e) { 434 } 435 }); 436 437 browser.addStatusTextListener(new StatusTextListener() { 440 public void changed(StatusTextEvent evt) { 441 statusBar.setText(" " + evt.text); 443 } 444 }); 445 446 browser.addTitleListener(new TitleListener() { 447 public void changed(TitleEvent evt) { 448 browser.getShell().setText(evt.title); 449 } 450 }); 451 452 browser.addLocationListener(new LocationListener() { 455 456 public void changed(LocationEvent evt) { 457 if (evt.top) { 458 setLocationText(evt.location); 459 } 460 } 461 462 public void changing(LocationEvent evt) { 463 String whitelistRuleFound = null; 464 String blacklistRuleFound = null; 465 if (evt.location.indexOf(":") == -1) { 466 evt.location = "file://" + evt.location; 467 } 468 String url = evt.location; 469 evt.doit = false; 470 471 if (BrowserWidgetHostChecker.isAlwaysWhitelisted(url)) { 475 evt.doit = true; 478 return; 479 } 480 whitelistRuleFound = BrowserWidgetHostChecker.matchWhitelisted(url); 481 blacklistRuleFound = BrowserWidgetHostChecker.matchBlacklisted(url); 482 483 evt.doit = whitelistRuleFound != null && blacklistRuleFound == null; 485 if (whitelistRuleFound == null && blacklistRuleFound == null) { 490 if (DialogBase.confirmAction( 491 (Shell) getParent(), 492 "Browsing to remote sites is a security risk! A malicious site could\r\n" 493 + "execute Java code though this browser window. Only click \"Yes\" if you\r\n" 494 + "are sure you trust the remote site. See the log for details and\r\n" 495 + "configuration instructions.\r\n" + "\r\n" + "\r\n" 496 + "Allow access to '" + url 497 + "' for the rest of this session?\r\n", "Security Warning")) { 498 evt.doit = true; 499 BrowserWidgetHostChecker.whitelistURL(url); 500 } else { 501 evt.doit = false; 502 BrowserWidgetHostChecker.blacklistURL(url); 503 } 504 } 505 506 if (!evt.doit) { 509 int lastQues = url.lastIndexOf('?'); 515 int lastSlash = url.lastIndexOf(File.pathSeparatorChar); 516 if (lastQues != -1 && lastQues > lastSlash) { 517 url = url.substring(0, lastQues); 518 } 519 520 if (!url.startsWith("http:") && !url.startsWith("https:")) { 525 File file = new File (url); 526 while (file != null) { 527 if (file.exists()) { 528 evt.doit = true; 529 break; 530 } else { 531 String msg = "Cannot find file '" + file.getAbsolutePath() 532 + "'"; 533 TreeLogger branch = logger.branch(TreeLogger.ERROR, msg, null); 534 if ("gwt-hosted.html".equalsIgnoreCase(file.getName())) { 535 branch.log( 536 TreeLogger.ERROR, 537 "If you want to open compiled output within this hosted browser, add '?gwt.hybrid' to the end of the URL", 538 null); 539 } 540 } 541 file = file.getParentFile(); 542 } 543 } 544 } 545 if (whitelistRuleFound == null || !evt.doit) { 547 String typeStr = "untrusted"; 549 if (blacklistRuleFound != null) { 550 typeStr = "blocked"; 551 } 552 TreeLogger header; 553 TreeLogger.Type msgType = TreeLogger.ERROR; 554 if (!evt.doit) { 555 header = logger.branch(msgType, "Unable to visit " + typeStr 556 + " URL: '" + url, null); 557 } else { 558 msgType = TreeLogger.WARN; 559 header = logger.branch(TreeLogger.WARN, 560 "Confirmation was required to visit " + typeStr + " URL: '" 561 + url, null); 562 } 563 if (blacklistRuleFound == null) { 564 BrowserWidgetHostChecker.notifyUntrustedHost(url, header, msgType); 565 } else { 566 BrowserWidgetHostChecker.notifyBlacklistedHost(blacklistRuleFound, 567 url, header, msgType); 568 } 569 setLocationText(browser.getUrl()); 570 } 571 } 572 573 }); 574 575 browser.addOpenWindowListener(new OpenWindowListener() { 578 public void open(WindowEvent event) { 579 try { 580 event.browser = host.openNewBrowserWindow().getBrowser(); 581 event.browser.getShell().open(); 582 } catch (UnableToCompleteException e) { 583 logger.log(TreeLogger.ERROR, "Unable to open new browser window", e); 584 } 585 } 586 }); 587 } 588 589 private void setLocationText(String text) { 590 location.setText(text); 591 int length = text.length(); 592 location.setSelection(length, length); 593 } 594 } 595 | Popular Tags |