| /* |
| * Copyright 2006 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 |
| * |
| * 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.google.gwt.dev.shell.ie; |
| |
| import com.google.gwt.core.ext.TreeLogger; |
| import com.google.gwt.dev.shell.BrowserWidget; |
| import com.google.gwt.dev.shell.BrowserWidgetHost; |
| import com.google.gwt.dev.shell.ModuleSpaceHost; |
| |
| import org.eclipse.swt.SWTException; |
| import org.eclipse.swt.internal.ole.win32.COM; |
| import org.eclipse.swt.internal.ole.win32.IDispatch; |
| import org.eclipse.swt.ole.win32.OleAutomation; |
| import org.eclipse.swt.ole.win32.Variant; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| |
| /** |
| * Represents an individual browser window and all of its controls. |
| */ |
| public class BrowserWidgetIE6 extends BrowserWidget { |
| |
| /** |
| * IDispatch implementation of the window.external object. |
| */ |
| public class External extends IDispatchImpl { |
| |
| /** |
| * Called by the loaded HTML page to activate a new module. |
| * |
| * @param frameWnd a reference to the IFRAME in which the module's injected |
| * JavaScript will live |
| * @param moduleName the name of the module to load, null if this is being |
| * unloaded |
| */ |
| public boolean gwtOnLoad(IDispatch frameWnd, String moduleName) { |
| try { |
| if (moduleName == null) { |
| // Indicates one or more modules are being unloaded. |
| handleUnload(frameWnd); |
| return true; |
| } |
| |
| // set the module ID |
| int moduleID = ++nextModuleID; |
| Integer key = new Integer(moduleID); |
| setIntProperty(frameWnd, "__gwt_module_id", moduleID); |
| |
| // Attach a new ModuleSpace to make it programmable. |
| // |
| ModuleSpaceHost msh = getHost().createModuleSpaceHost( |
| BrowserWidgetIE6.this, moduleName); |
| ModuleSpaceIE6 moduleSpace = new ModuleSpaceIE6(msh, frameWnd, |
| moduleName, key); |
| attachModuleSpace(moduleSpace); |
| return true; |
| } catch (Throwable e) { |
| // We do catch Throwable intentionally because there are a ton of things |
| // that can go wrong trying to load a module, including Error-derived |
| // things like NoClassDefFoundError. |
| // |
| getHost().getLogger().log(TreeLogger.ERROR, |
| "Failure to load module '" + moduleName + "'", e); |
| return false; |
| } |
| } |
| |
| protected void getIDsOfNames(String[] names, int[] ids) |
| throws HResultException { |
| |
| if (names.length >= 2) { |
| throw new HResultException(DISP_E_UNKNOWNNAME); |
| } |
| |
| String name = names[0].toLowerCase(); |
| if (name.equals("gwtonload")) { |
| ids[0] = 1; |
| return; |
| } |
| |
| throw new HResultException(DISP_E_UNKNOWNNAME); |
| } |
| |
| /** |
| * Unload one or more modules. |
| * |
| * @param frameWnd window to unload, null if all |
| */ |
| protected void handleUnload(IDispatch frameWnd) { |
| Integer key = null; |
| if (frameWnd != null) { |
| key = new Integer(getIntProperty(frameWnd, "__gwt_module_id")); |
| } |
| doUnload(key); |
| } |
| |
| protected Variant invoke(int dispId, int flags, Variant[] params) |
| throws HResultException, InvocationTargetException { |
| |
| if (dispId == 0 && (flags & COM.DISPATCH_PROPERTYGET) != 0) { |
| // MAGIC: this is the default property, let's just do toString() |
| return new Variant(toString()); |
| } else if (dispId == 1) { |
| if ((flags & COM.DISPATCH_METHOD) != 0) { |
| try { |
| IDispatch frameWnd = (params[0].getType() == COM.VT_DISPATCH) |
| ? params[0].getDispatch() : null; |
| String moduleName = (params[1].getType() == COM.VT_BSTR) |
| ? params[1].getString() : null; |
| boolean success = gwtOnLoad(frameWnd, moduleName); |
| |
| // boolean return type |
| return new Variant(success); |
| } catch (SWTException e) { |
| throw new HResultException(COM.E_INVALIDARG); |
| } |
| } else if ((flags & COM.DISPATCH_PROPERTYGET) != 0) { |
| // property get on the method itself |
| try { |
| Method gwtOnLoadMethod = getClass().getMethod("gwtOnLoad", |
| new Class[] {IDispatch.class, String.class}); |
| IDispatchImpl funcObj = new MethodDispatch(null, gwtOnLoadMethod); |
| IDispatch disp = new IDispatch(funcObj.getAddress()); |
| disp.AddRef(); |
| return new Variant(disp); |
| } catch (Exception e) { |
| // just return VT_EMPTY |
| return new Variant(); |
| } |
| } |
| throw new HResultException(COM.E_NOTSUPPORTED); |
| } |
| |
| // The specified member id is out of range. |
| throw new HResultException(COM.DISP_E_MEMBERNOTFOUND); |
| } |
| } |
| |
| // counter to generate unique module IDs |
| private static int nextModuleID = 0; |
| |
| /** |
| * Get a property off a window object as an integer. |
| * |
| * @param frameWnd inner code frame |
| * @param propName name of the property to get |
| * @return the property value as an integer |
| * @throws RuntimeException if the property does not exist |
| */ |
| private static int getIntProperty(IDispatch frameWnd, String propName) { |
| OleAutomation window = null; |
| try { |
| window = new OleAutomation(frameWnd); |
| int[] dispID = window.getIDsOfNames(new String[] { propName }); |
| if (dispID == null) { |
| throw new RuntimeException("No such property " + propName); |
| } |
| Variant value = null; |
| try { |
| value = window.getProperty(dispID[0]); |
| return value.getInt(); |
| } finally { |
| if (value != null) { |
| value.dispose(); |
| } |
| } |
| } finally { |
| if (window != null) { |
| window.dispose(); |
| } |
| } |
| } |
| |
| /** |
| * Set a property off a window object from an integer value. |
| * |
| * @param frameWnd inner code frame |
| * @param propName name of the property to set |
| * @param intValue the value to set |
| * @throws RuntimeException if the property does not exist |
| */ |
| private static void setIntProperty(IDispatch frameWnd, String propName, |
| int intValue) { |
| OleAutomation window = null; |
| try { |
| window = new OleAutomation(frameWnd); |
| int[] dispID = window.getIDsOfNames(new String[] { propName }); |
| if (dispID == null) { |
| throw new RuntimeException("No such property " + propName); |
| } |
| Variant value = null; |
| try { |
| value = new Variant(intValue); |
| window.setProperty(dispID[0], value); |
| } finally { |
| if (value != null) { |
| value.dispose(); |
| } |
| } |
| } finally { |
| if (window != null) { |
| window.dispose(); |
| } |
| } |
| } |
| |
| public BrowserWidgetIE6(Shell shell, BrowserWidgetHost host) { |
| super(shell, host); |
| |
| // Expose a 'window.external' object. This object's onLoad() method will |
| // be called when a hosted mode application's wrapper HTML is done loading. |
| // |
| SwtOleGlue.injectBrowserScriptExternalObject(browser, new External()); |
| |
| // Make sure that the LowLevelIE6 magic is properly initialized. |
| // |
| LowLevelIE6.init(); |
| } |
| } |