001: /*
002: * Copyright 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.shell.ie;
017:
018: import com.google.gwt.core.ext.TreeLogger;
019: import com.google.gwt.dev.shell.BrowserWidget;
020: import com.google.gwt.dev.shell.BrowserWidgetHost;
021: import com.google.gwt.dev.shell.ModuleSpaceHost;
022:
023: import org.eclipse.swt.SWTException;
024: import org.eclipse.swt.internal.ole.win32.COM;
025: import org.eclipse.swt.internal.ole.win32.IDispatch;
026: import org.eclipse.swt.ole.win32.OleAutomation;
027: import org.eclipse.swt.ole.win32.Variant;
028: import org.eclipse.swt.widgets.Shell;
029:
030: import java.lang.reflect.InvocationTargetException;
031: import java.lang.reflect.Method;
032:
033: /**
034: * Represents an individual browser window and all of its controls.
035: */
036: public class BrowserWidgetIE6 extends BrowserWidget {
037:
038: /**
039: * IDispatch implementation of the window.external object.
040: */
041: public class External extends IDispatchImpl {
042:
043: /**
044: * Called by the loaded HTML page to activate a new module.
045: *
046: * @param frameWnd a reference to the IFRAME in which the module's injected
047: * JavaScript will live
048: * @param moduleName the name of the module to load, null if this is being
049: * unloaded
050: */
051: public boolean gwtOnLoad(IDispatch frameWnd, String moduleName) {
052: try {
053: if (moduleName == null) {
054: // Indicates one or more modules are being unloaded.
055: handleUnload(frameWnd);
056: return true;
057: }
058:
059: // set the module ID
060: int moduleID = ++nextModuleID;
061: Integer key = new Integer(moduleID);
062: setIntProperty(frameWnd, "__gwt_module_id", moduleID);
063:
064: // Attach a new ModuleSpace to make it programmable.
065: //
066: ModuleSpaceHost msh = getHost().createModuleSpaceHost(
067: BrowserWidgetIE6.this , moduleName);
068: ModuleSpaceIE6 moduleSpace = new ModuleSpaceIE6(msh,
069: frameWnd, moduleName, key);
070: attachModuleSpace(moduleSpace);
071: return true;
072: } catch (Throwable e) {
073: // We do catch Throwable intentionally because there are a ton of things
074: // that can go wrong trying to load a module, including Error-derived
075: // things like NoClassDefFoundError.
076: //
077: getHost().getLogger().log(TreeLogger.ERROR,
078: "Failure to load module '" + moduleName + "'",
079: e);
080: return false;
081: }
082: }
083:
084: @Override
085: protected void getIDsOfNames(String[] names, int[] ids)
086: throws HResultException {
087:
088: if (names.length >= 2) {
089: throw new HResultException(DISP_E_UNKNOWNNAME);
090: }
091:
092: String name = names[0].toLowerCase();
093: if (name.equals("gwtonload")) {
094: ids[0] = 1;
095: return;
096: }
097:
098: throw new HResultException(DISP_E_UNKNOWNNAME);
099: }
100:
101: /**
102: * Unload one or more modules.
103: *
104: * @param frameWnd window to unload, null if all
105: */
106: protected void handleUnload(IDispatch frameWnd) {
107: Integer key = null;
108: if (frameWnd != null) {
109: key = new Integer(getIntProperty(frameWnd,
110: "__gwt_module_id"));
111: }
112: doUnload(key);
113: }
114:
115: @Override
116: protected Variant invoke(int dispId, int flags, Variant[] params)
117: throws HResultException, InvocationTargetException {
118:
119: if (dispId == 0 && (flags & COM.DISPATCH_PROPERTYGET) != 0) {
120: // MAGIC: this is the default property, let's just do toString()
121: return new Variant(toString());
122: } else if (dispId == 1) {
123: if ((flags & COM.DISPATCH_METHOD) != 0) {
124: try {
125: IDispatch frameWnd = (params[0].getType() == COM.VT_DISPATCH) ? params[0]
126: .getDispatch()
127: : null;
128: String moduleName = (params[1].getType() == COM.VT_BSTR) ? params[1]
129: .getString()
130: : null;
131: boolean success = gwtOnLoad(frameWnd,
132: moduleName);
133:
134: // boolean return type
135: return new Variant(success);
136: } catch (SWTException e) {
137: throw new HResultException(COM.E_INVALIDARG);
138: }
139: } else if ((flags & COM.DISPATCH_PROPERTYGET) != 0) {
140: // property get on the method itself
141: try {
142: Method gwtOnLoadMethod = getClass().getMethod(
143: "gwtOnLoad",
144: new Class[] { IDispatch.class,
145: String.class });
146: IDispatchImpl funcObj = new MethodDispatch(
147: null, gwtOnLoadMethod);
148: IDispatch disp = new IDispatch(funcObj
149: .getAddress());
150: disp.AddRef();
151: return new Variant(disp);
152: } catch (Exception e) {
153: // just return VT_EMPTY
154: return new Variant();
155: }
156: }
157: throw new HResultException(COM.E_NOTSUPPORTED);
158: }
159:
160: // The specified member id is out of range.
161: throw new HResultException(COM.DISP_E_MEMBERNOTFOUND);
162: }
163: }
164:
165: // counter to generate unique module IDs
166: private static int nextModuleID = 0;
167:
168: /**
169: * Get a property off a window object as an integer.
170: *
171: * @param frameWnd inner code frame
172: * @param propName name of the property to get
173: * @return the property value as an integer
174: * @throws RuntimeException if the property does not exist
175: */
176: private static int getIntProperty(IDispatch frameWnd,
177: String propName) {
178: OleAutomation window = null;
179: try {
180: window = new OleAutomation(frameWnd);
181: int[] dispID = window
182: .getIDsOfNames(new String[] { propName });
183: if (dispID == null) {
184: throw new RuntimeException("No such property "
185: + propName);
186: }
187: Variant value = null;
188: try {
189: value = window.getProperty(dispID[0]);
190: return value.getInt();
191: } finally {
192: if (value != null) {
193: value.dispose();
194: }
195: }
196: } finally {
197: if (window != null) {
198: window.dispose();
199: }
200: }
201: }
202:
203: /**
204: * Set a property off a window object from an integer value.
205: *
206: * @param frameWnd inner code frame
207: * @param propName name of the property to set
208: * @param intValue the value to set
209: * @throws RuntimeException if the property does not exist
210: */
211: private static void setIntProperty(IDispatch frameWnd,
212: String propName, int intValue) {
213: OleAutomation window = null;
214: try {
215: window = new OleAutomation(frameWnd);
216: int[] dispID = window
217: .getIDsOfNames(new String[] { propName });
218: if (dispID == null) {
219: throw new RuntimeException("No such property "
220: + propName);
221: }
222: Variant value = null;
223: try {
224: value = new Variant(intValue);
225: window.setProperty(dispID[0], value);
226: } finally {
227: if (value != null) {
228: value.dispose();
229: }
230: }
231: } finally {
232: if (window != null) {
233: window.dispose();
234: }
235: }
236: }
237:
238: public BrowserWidgetIE6(Shell shell, BrowserWidgetHost host) {
239: super (shell, host);
240:
241: // Expose a 'window.external' object. This object's onLoad() method will
242: // be called when a hosted mode application's wrapper HTML is done loading.
243: //
244: SwtOleGlue.injectBrowserScriptExternalObject(browser,
245: new External());
246:
247: // Make sure that the LowLevelIE6 magic is properly initialized.
248: //
249: LowLevelIE6.init();
250: }
251:
252: @Override
253: public String getUserAgent() {
254: // See UserAgent.gwt.xml
255: return "ie6";
256: }
257: }
|