]> git.saurik.com Git - wxWidgets.git/blob - wxPython/contrib/iewin/IEHtmlWin.cpp
Faster Deselect
[wxWidgets.git] / wxPython / contrib / iewin / IEHtmlWin.cpp
1 #include "IEHtmlWin.h"
2 #include <wx/strconv.h>
3 #include <wx/string.h>
4 #include <wx/event.h>
5 #include <wx/listctrl.h>
6 #include <wx/mstream.h>
7 #include <oleidl.h>
8 #include <winerror.h>
9 #include <exdispid.h>
10 #include <exdisp.h>
11 #include <olectl.h>
12 #include <Mshtml.h>
13 #include <sstream>
14 using namespace std;
15
16 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2);
17 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_NEWWINDOW2);
18 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE);
19 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE);
20 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE);
21 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_TITLECHANGE);
22
23 IMPLEMENT_DYNAMIC_CLASS(wxMSHTMLEvent, wxNotifyEvent);
24
25
26 //////////////////////////////////////////////////////////////////////
27 BEGIN_EVENT_TABLE(wxIEHtmlWin, wxActiveX)
28 END_EVENT_TABLE()
29
30 class FS_DWebBrowserEvents2 : public IDispatch
31 {
32 private:
33 DECLARE_OLE_UNKNOWN(FS_DWebBrowserEvents2);
34
35
36 wxIEHtmlWin *m_iewin;
37
38 public:
39 FS_DWebBrowserEvents2(wxIEHtmlWin *iewin) : m_iewin(iewin) {}
40 virtual ~FS_DWebBrowserEvents2()
41 {
42 }
43
44 //IDispatch
45 STDMETHODIMP GetIDsOfNames(REFIID r, OLECHAR** o, unsigned int i, LCID l, DISPID* d)
46 {
47 return E_NOTIMPL;
48 };
49
50 STDMETHODIMP GetTypeInfo(unsigned int i, LCID l, ITypeInfo** t)
51 {
52 return E_NOTIMPL;
53 };
54
55 STDMETHODIMP GetTypeInfoCount(unsigned int* i)
56 {
57 return E_NOTIMPL;
58 };
59
60 void Post(WXTYPE etype, wxString text, long l1 = 0, long l2 = 0)
61 {
62 if (! m_iewin || ! m_iewin->GetParent())
63 return;
64
65 wxMSHTMLEvent event;
66 event.SetId(m_iewin->GetId());
67 event.SetEventType(etype);
68 event.m_text1 = text;
69 event.m_long1 = l1;
70 event.m_long2 = l2;
71
72 m_iewin->GetParent()->AddPendingEvent(event);
73 };
74
75 bool Process(WXTYPE etype, wxString text = wxEmptyString, long l1 = 0, long l2 = 0)
76 {
77 if (! m_iewin || ! m_iewin->GetParent())
78 return true;
79
80 wxMSHTMLEvent event;
81 event.SetId(m_iewin->GetId());
82 event.SetEventType(etype);
83 event.m_text1 = text;
84 event.m_long1 = l1;
85 event.m_long2 = l2;
86
87 m_iewin->GetParent()->ProcessEvent(event);
88
89 return event.IsAllowed();
90 };
91
92 wxString GetStrArg(VARIANT& v)
93 {
94 VARTYPE vt = v.vt & ~VT_BYREF;
95
96 if (vt == VT_VARIANT)
97 return GetStrArg(*v.pvarVal);
98 else if (vt == VT_BSTR)
99 {
100 if (v.vt & VT_BYREF)
101 return (v.pbstrVal ? *v.pbstrVal : L"");
102 else
103 return v.bstrVal;
104 }
105 else
106 return wxEmptyString;
107 };
108
109 #define STR_ARG(arg) GetStrArg(pDispParams->rgvarg[arg])
110
111 #define LONG_ARG(arg)\
112 (pDispParams->rgvarg[arg].lVal)
113
114
115 STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
116 WORD wFlags, DISPPARAMS * pDispParams,
117 VARIANT * pVarResult, EXCEPINFO * pExcepInfo,
118 unsigned int * puArgErr)
119 {
120 if (wFlags & DISPATCH_PROPERTYGET)
121 return E_NOTIMPL;
122
123 switch (dispIdMember)
124 {
125 case DISPID_BEFORENAVIGATE2:
126 if (Process(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2, STR_ARG(5)))
127 *pDispParams->rgvarg->pboolVal = VARIANT_FALSE;
128 else
129 *pDispParams->rgvarg->pboolVal = VARIANT_TRUE;
130 break;
131
132 case DISPID_NEWWINDOW2:
133 if (Process(wxEVT_COMMAND_MSHTML_NEWWINDOW2))
134 *pDispParams->rgvarg->pboolVal = VARIANT_FALSE;
135 else
136 *pDispParams->rgvarg->pboolVal = VARIANT_TRUE;
137 break;
138
139 case DISPID_PROGRESSCHANGE:
140 Post(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE, wxEmptyString, LONG_ARG(1), LONG_ARG(0));
141 break;
142
143 case DISPID_DOCUMENTCOMPLETE:
144 Post(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE, STR_ARG(0));
145 break;
146
147 case DISPID_STATUSTEXTCHANGE:
148 Post(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE, STR_ARG(0));
149 break;
150
151 case DISPID_TITLECHANGE:
152 Post(wxEVT_COMMAND_MSHTML_TITLECHANGE, STR_ARG(0));
153 break;
154 }
155
156 return S_OK;
157 }
158 };
159
160 #undef STR_ARG
161
162 DEFINE_OLE_TABLE(FS_DWebBrowserEvents2)
163 OLE_IINTERFACE(IUnknown)
164 OLE_INTERFACE(DIID_DWebBrowserEvents2, DWebBrowserEvents2)
165 END_OLE_TABLE;
166
167
168 static const CLSID CLSID_MozillaBrowser =
169 { 0x1339B54C, 0x3453, 0x11D2,
170 { 0x93, 0xB9, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00 } };
172
173
174 //#define PROGID "Shell.Explorer"
175 #define PROGID CLSID_WebBrowser
176 //#define PROGID CLSID_MozillaBrowser
177 //#define PROGID CLSID_HTMLDocument
178 //#define PROGID "MSCAL.Calendar"
179 //#define PROGID "WordPad.Document.1"
180 //#define PROGID "SoftwareFX.ChartFX.20"
181
182 wxIEHtmlWin::wxIEHtmlWin(wxWindow * parent, wxWindowID id,
183 const wxPoint& pos,
184 const wxSize& size,
185 long style,
186 const wxString& name) :
187 wxActiveX(parent, PROGID, id, pos, size, style, name)
188 {
189 SetupBrowser();
190 }
191
192
193 wxIEHtmlWin::~wxIEHtmlWin()
194 {
195 }
196
197 void wxIEHtmlWin::SetupBrowser()
198 {
199 HRESULT hret;
200
201 // Get IWebBrowser2 Interface
202 hret = m_webBrowser.QueryInterface(IID_IWebBrowser2, m_ActiveX);
203 assert(SUCCEEDED(hret));
204
205 // Web Browser Events
206 FS_DWebBrowserEvents2 *events = new FS_DWebBrowserEvents2(this);
207 hret = ConnectAdvise(DIID_DWebBrowserEvents2, events);
208 if (! SUCCEEDED(hret))
209 delete events;
210
211 // web browser setup
212 m_webBrowser->put_MenuBar(VARIANT_FALSE);
213 m_webBrowser->put_AddressBar(VARIANT_FALSE);
214 m_webBrowser->put_StatusBar(VARIANT_FALSE);
215 m_webBrowser->put_ToolBar(VARIANT_FALSE);
216
217 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
218 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
219
220 m_webBrowser->Navigate( L"about:blank", NULL, NULL, NULL, NULL );
221 }
222
223
224 void wxIEHtmlWin::SetEditMode(bool seton)
225 {
226 m_bAmbientUserMode = ! seton;
227 AmbientPropertyChanged(DISPID_AMBIENT_USERMODE);
228 };
229
230 bool wxIEHtmlWin::GetEditMode()
231 {
232 return ! m_bAmbientUserMode;
233 };
234
235
236 void wxIEHtmlWin::SetCharset(wxString charset)
237 {
238 // HTML Document ?
239 IDispatch *pDisp = NULL;
240 HRESULT hret = m_webBrowser->get_Document(&pDisp);
241 wxAutoOleInterface<IDispatch> disp(pDisp);
242
243 if (disp.Ok())
244 {
245 wxAutoOleInterface<IHTMLDocument2> doc(IID_IHTMLDocument2, disp);
246 if (doc.Ok())
247 doc->put_charset((BSTR) (const wchar_t *) charset.wc_str(wxConvUTF8));
248 //doc->put_charset((BSTR) wxConvUTF8.cMB2WC(charset).data());
249 };
250 };
251
252
253 class IStreamAdaptorBase : public IStream
254 {
255 private:
256 DECLARE_OLE_UNKNOWN(IStreamAdaptorBase);
257
258 public:
259 IStreamAdaptorBase() {}
260 virtual ~IStreamAdaptorBase() {}
261
262 // ISequentialStream
263 HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead) = 0;
264 HRESULT STDMETHODCALLTYPE Write(const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten) {return E_NOTIMPL;}
265
266 // IStream
267 HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER __RPC_FAR *plibNewPosition) {return E_NOTIMPL;}
268 HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) {return E_NOTIMPL;}
269 HRESULT STDMETHODCALLTYPE CopyTo(IStream __RPC_FAR *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER __RPC_FAR *pcbRead, ULARGE_INTEGER __RPC_FAR *pcbWritten) {return E_NOTIMPL;}
270 HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) {return E_NOTIMPL;}
271 HRESULT STDMETHODCALLTYPE Revert(void) {return E_NOTIMPL;}
272 HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {return E_NOTIMPL;}
273 HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {return E_NOTIMPL;}
274 HRESULT STDMETHODCALLTYPE Stat(STATSTG __RPC_FAR *pstatstg, DWORD grfStatFlag) {return E_NOTIMPL;}
275 HRESULT STDMETHODCALLTYPE Clone(IStream __RPC_FAR *__RPC_FAR *ppstm) {return E_NOTIMPL;}
276 };
277
278 DEFINE_OLE_TABLE(IStreamAdaptorBase)
279 OLE_IINTERFACE(IUnknown)
280 OLE_IINTERFACE(ISequentialStream)
281 OLE_IINTERFACE(IStream)
282 END_OLE_TABLE;
283
284 class IStreamAdaptor : public IStreamAdaptorBase
285 {
286 private:
287 istream *m_is;
288
289 public:
290
291 IStreamAdaptor(istream *is) : IStreamAdaptorBase(), m_is(is)
292 {
293 wxASSERT(m_is != NULL);
294 }
295 ~IStreamAdaptor()
296 {
297 delete m_is;
298 }
299
300 // ISequentialStream
301 HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead)
302 {
303 m_is->read((char *) pv, cb);
304 if (pcbRead)
305 *pcbRead = m_is->gcount();
306
307 return S_OK;
308 };
309 };
310
311 class IwxStreamAdaptor : public IStreamAdaptorBase
312 {
313 private:
314 wxInputStream *m_is;
315
316 public:
317
318 IwxStreamAdaptor(wxInputStream *is) : IStreamAdaptorBase(), m_is(is)
319 {
320 wxASSERT(m_is != NULL);
321 }
322 ~IwxStreamAdaptor()
323 {
324 delete m_is;
325 }
326
327 // ISequentialStream
328 HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead)
329 {
330 m_is->Read((char *) pv, cb);
331 if (pcbRead)
332 *pcbRead = m_is->LastRead();
333
334 return S_OK;
335 };
336 };
337
338 void wxIEHtmlWin::LoadUrl(const wxString& url)
339 {
340 VARIANTARG navFlag, targetFrame, postData, headers;
341 navFlag.vt = VT_EMPTY;
342 navFlag.vt = VT_I2;
343 navFlag.iVal = navNoReadFromCache;
344 targetFrame.vt = VT_EMPTY;
345 postData.vt = VT_EMPTY;
346 headers.vt = VT_EMPTY;
347
348 HRESULT hret = 0;
349 hret = m_webBrowser->Navigate((BSTR) (const wchar_t *) url.wc_str(wxConvUTF8),
350 &navFlag, &targetFrame, &postData, &headers);
351 };
352
353 class wxOwnedMemInputStream : public wxMemoryInputStream
354 {
355 public:
356 char *m_data;
357
358 wxOwnedMemInputStream(char *data, size_t len) :
359 wxMemoryInputStream(data, len), m_data(data)
360 {}
361 ~wxOwnedMemInputStream()
362 {
363 free(m_data);
364 }
365 };
366
367 bool wxIEHtmlWin::LoadString(wxString html)
368 {
369 char *data = NULL;
370 size_t len = html.length();
371 #ifdef UNICODE
372 len *= 2;
373 #endif
374 data = (char *) malloc(len);
375 memcpy(data, html.c_str(), len);
376 return LoadStream(new wxOwnedMemInputStream(data, len));
377 };
378
379 bool wxIEHtmlWin::LoadStream(IStreamAdaptorBase *pstrm)
380 {
381 wxAutoOleInterface<IStream> strm(pstrm);
382
383 // Document Interface
384 IDispatch *pDisp = NULL;
385 HRESULT hret = m_webBrowser->get_Document(&pDisp);
386 if (! pDisp)
387 return false;
388 wxAutoOleInterface<IDispatch> disp(pDisp);
389
390
391 // get IPersistStreamInit
392 wxAutoOleInterface<IPersistStreamInit>
393 pPersistStreamInit(IID_IPersistStreamInit, disp);
394
395 if (pPersistStreamInit.Ok())
396 {
397 HRESULT hr = pPersistStreamInit->InitNew();
398 if (SUCCEEDED(hr))
399 hr = pPersistStreamInit->Load(strm);
400
401 return SUCCEEDED(hr);
402 }
403 else
404 return false;
405 };
406
407 bool wxIEHtmlWin::LoadStream(istream *is)
408 {
409 // wrap reference around stream
410 IStreamAdaptor *pstrm = new IStreamAdaptor(is);
411 pstrm->AddRef();
412
413 return LoadStream(pstrm);
414 };
415
416 bool wxIEHtmlWin::LoadStream(wxInputStream *is)
417 {
418 // wrap reference around stream
419 IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is);
420 pstrm->AddRef();
421
422 return LoadStream(pstrm);
423 };
424
425
426 bool wxIEHtmlWin::GoBack()
427 {
428 HRESULT hret = 0;
429 hret = m_webBrowser->GoBack();
430 return hret == S_OK;
431 }
432
433 bool wxIEHtmlWin::GoForward()
434 {
435 HRESULT hret = 0;
436 hret = m_webBrowser->GoForward();
437 return hret == S_OK;
438 }
439
440 bool wxIEHtmlWin::GoHome()
441 {
442 HRESULT hret = 0;
443 hret = m_webBrowser->GoHome();
444 return hret == S_OK;
445 }
446
447 bool wxIEHtmlWin::GoSearch()
448 {
449 HRESULT hret = 0;
450 hret = m_webBrowser->GoSearch();
451 return hret == S_OK;
452 }
453
454 bool wxIEHtmlWin::Refresh(wxIEHtmlRefreshLevel level)
455 {
456 VARIANTARG levelArg;
457 HRESULT hret = 0;
458
459 levelArg.vt = VT_I2;
460 levelArg.iVal = level;
461 hret = m_webBrowser->Refresh2(&levelArg);
462 return hret == S_OK;
463 }
464
465 bool wxIEHtmlWin::Stop()
466 {
467 HRESULT hret = 0;
468 hret = m_webBrowser->Stop();
469 return hret == S_OK;
470 }
471
472
473 ///////////////////////////////////////////////////////////////////////////////
474
475 static wxAutoOleInterface<IHTMLSelectionObject> GetSelObject(IOleObject *oleObject)
476 {
477 // Query for IWebBrowser interface
478 wxAutoOleInterface<IWebBrowser2> wb(IID_IWebBrowser2, oleObject);
479 if (! wb.Ok())
480 return wxAutoOleInterface<IHTMLSelectionObject>();
481
482 IDispatch *iDisp = NULL;
483 HRESULT hr = wb->get_Document(&iDisp);
484 if (hr != S_OK)
485 return wxAutoOleInterface<IHTMLSelectionObject>();
486
487 // Query for Document Interface
488 wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
489 iDisp->Release();
490
491 if (! hd.Ok())
492 return wxAutoOleInterface<IHTMLSelectionObject>();
493
494 IHTMLSelectionObject *_so = NULL;
495 hr = hd->get_selection(&_so);
496
497 // take ownership of selection object
498 wxAutoOleInterface<IHTMLSelectionObject> so(_so);
499
500 return so;
501 };
502
503 static wxAutoOleInterface<IHTMLTxtRange> GetSelRange(IOleObject *oleObject)
504 {
505 wxAutoOleInterface<IHTMLTxtRange> tr;
506
507 wxAutoOleInterface<IHTMLSelectionObject> so(GetSelObject(oleObject));
508 if (! so)
509 return tr;
510
511 IDispatch *iDisp = NULL;
512 HRESULT hr = so->createRange(&iDisp);
513 if (hr != S_OK)
514 return tr;
515
516 // Query for IHTMLTxtRange interface
517 tr.QueryInterface(IID_IHTMLTxtRange, iDisp);
518 iDisp->Release();
519 return tr;
520 };
521
522
523 wxString wxIEHtmlWin::GetStringSelection(bool asHTML)
524 {
525 wxAutoOleInterface<IHTMLTxtRange> tr(GetSelRange(m_oleObject));
526 if (! tr)
527 return wxEmptyString;
528
529 BSTR text = NULL;
530 HRESULT hr = E_FAIL;
531
532 if (asHTML)
533 hr = tr->get_htmlText(&text);
534 else
535 hr = tr->get_text(&text);
536 if (hr != S_OK)
537 return wxEmptyString;
538
539 wxString s = text;
540 SysFreeString(text);
541
542 return s;
543 };
544
545 wxString wxIEHtmlWin::GetText(bool asHTML)
546 {
547 if (! m_webBrowser.Ok())
548 return wxEmptyString;
549
550 // get document dispatch interface
551 IDispatch *iDisp = NULL;
552 HRESULT hr = m_webBrowser->get_Document(&iDisp);
553 if (hr != S_OK)
554 return wxEmptyString;
555
556 // Query for Document Interface
557 wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
558 iDisp->Release();
559
560 if (! hd.Ok())
561 return wxEmptyString;
562
563 // get body element
564 IHTMLElement *_body = NULL;
565 hd->get_body(&_body);
566 if (! _body)
567 return wxEmptyString;
568 wxAutoOleInterface<IHTMLElement> body(_body);
569
570 // get inner text
571 BSTR text = NULL;
572 hr = E_FAIL;
573
574 if (asHTML)
575 hr = body->get_innerHTML(&text);
576 else
577 hr = body->get_innerText(&text);
578 if (hr != S_OK)
579 return wxEmptyString;
580
581 wxString s = text;
582 SysFreeString(text);
583
584 return s;
585 };