]> git.saurik.com Git - wxWidgets.git/blob - src/msw/webview_ie.cpp
Implement basic support for virtual file systems for the ie backend. Registering...
[wxWidgets.git] / src / msw / webview_ie.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/webview_ie.cpp
3 // Purpose: wxMSW wxWebViewIE class implementation for web view component
4 // Author: Marianne Gagnon
5 // Id: $Id$
6 // Copyright: (c) 2010 Marianne Gagnon, Steven Lamerton
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if defined(__BORLANDC__)
14 #pragma hdrstop
15 #endif
16
17 #include "wx/msw/webview_ie.h"
18
19 #if wxUSE_WEBVIEW_IE
20
21 #include <olectl.h>
22 #include <oleidl.h>
23 #include <exdispid.h>
24 #include <exdisp.h>
25 #include <mshtml.h>
26 #include "wx/msw/registry.h"
27 #include "wx/msw/missing.h"
28 #include "wx/filesys.h"
29
30 //Taken from wx/filesys.cpp
31 static wxString EscapeFileNameCharsInURL(const char *in)
32 {
33 wxString s;
34
35 for ( const unsigned char *p = (const unsigned char*)in; *p; ++p )
36 {
37 const unsigned char c = *p;
38
39 if ( c == '/' || c == '-' || c == '.' || c == '_' || c == '~' ||
40 (c >= '0' && c <= '9') ||
41 (c >= 'a' && c <= 'z') ||
42 (c >= 'A' && c <= 'Z') )
43 {
44 s << c;
45 }
46 else
47 {
48 s << wxString::Format("%%%02x", c);
49 }
50 }
51
52 return s;
53 }
54
55 BEGIN_EVENT_TABLE(wxWebViewIE, wxControl)
56 EVT_ACTIVEX(wxID_ANY, wxWebViewIE::onActiveXEvent)
57 EVT_ERASE_BACKGROUND(wxWebViewIE::onEraseBg)
58 END_EVENT_TABLE()
59
60 bool wxWebViewIE::Create(wxWindow* parent,
61 wxWindowID id,
62 const wxString& url,
63 const wxPoint& pos,
64 const wxSize& size,
65 long style,
66 const wxString& name)
67 {
68 if (!wxControl::Create(parent, id, pos, size, style,
69 wxDefaultValidator, name))
70 {
71 return false;
72 }
73
74 m_webBrowser = NULL;
75 m_canNavigateBack = false;
76 m_canNavigateForward = false;
77 m_isBusy = false;
78 m_historyLoadingFromList = false;
79 m_historyEnabled = true;
80 m_historyPosition = -1;
81 m_zoomType = wxWEB_VIEW_ZOOM_TYPE_TEXT;
82
83 if (::CoCreateInstance(CLSID_WebBrowser, NULL,
84 CLSCTX_INPROC_SERVER, // CLSCTX_INPROC,
85 IID_IWebBrowser2 , (void**)&m_webBrowser) != 0)
86 {
87 wxLogError("Failed to initialize IE, CoCreateInstance returned an error");
88 return false;
89 }
90
91 m_ie.SetDispatchPtr(m_webBrowser); // wxAutomationObject will release itself
92
93 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
94 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
95 //m_webBrowser->put_Silent(VARIANT_FALSE);
96
97 //We register a custom handler for the file protocol so we can handle
98 //Virtual file systems
99 ClassFactory* cf = new ClassFactory;
100 IInternetSession* session;
101 if(CoInternetGetSession(0, &session, 0) != S_OK)
102 return false;
103 HRESULT hr = session->RegisterNameSpace(cf, CLSID_FileProtocol, L"file", 0, NULL, 0);
104 if(FAILED(hr))
105 return false;
106
107 m_container = new wxActiveXContainer(this, IID_IWebBrowser2, m_webBrowser);
108
109 SetBackgroundStyle(wxBG_STYLE_PAINT);
110 SetDoubleBuffered(true);
111 LoadUrl(url);
112 return true;
113 }
114
115
116 void wxWebViewIE::LoadUrl(const wxString& url)
117 {
118 m_ie.CallMethod("Navigate", (BSTR) url.wc_str(), NULL, NULL, NULL, NULL);
119 }
120
121 void wxWebViewIE::SetPage(const wxString& html, const wxString& baseUrl)
122 {
123 BSTR bstr = SysAllocString(html.wc_str());
124
125 // Creates a new one-dimensional array
126 SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
127 if (psaStrings != NULL)
128 {
129 VARIANT *param;
130
131 HRESULT hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
132 param->vt = VT_BSTR;
133 param->bstrVal = bstr;
134 hr = SafeArrayUnaccessData(psaStrings);
135
136 IHTMLDocument2* document = GetDocument();
137 document->write(psaStrings);
138 document->Release();
139
140 // SafeArrayDestroy calls SysFreeString for each BSTR
141 SafeArrayDestroy(psaStrings);
142
143 //We send the events when we are done to mimic webkit
144 //Navigated event
145 wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
146 GetId(), baseUrl, "", false);
147 event.SetEventObject(this);
148 HandleWindowEvent(event);
149
150 //Document complete event
151 event.SetEventType(wxEVT_COMMAND_WEB_VIEW_LOADED);
152 event.SetEventObject(this);
153 HandleWindowEvent(event);
154 }
155 else
156 {
157 wxLogError("wxWebViewIE::SetPage() : psaStrings is NULL");
158 }
159
160 }
161
162 wxString wxWebViewIE::GetPageSource()
163 {
164 IHTMLDocument2* document = GetDocument();
165 IHTMLElement *bodyTag = NULL;
166 IHTMLElement *htmlTag = NULL;
167 wxString source;
168 HRESULT hr = document->get_body(&bodyTag);
169 if(SUCCEEDED(hr))
170 {
171 hr = bodyTag->get_parentElement(&htmlTag);
172 if(SUCCEEDED(hr))
173 {
174 BSTR bstr;
175 htmlTag->get_outerHTML(&bstr);
176 source = wxString(bstr);
177 htmlTag->Release();
178 }
179 bodyTag->Release();
180 }
181
182 document->Release();
183 return source;
184 }
185
186 wxWebViewZoom wxWebViewIE::GetZoom()
187 {
188 if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_LAYOUT)
189 return GetIEOpticalZoom();
190 else if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_TEXT)
191 return GetIETextZoom();
192 else
193 wxFAIL;
194
195 //Dummy return to stop compiler warnings
196 return wxWEB_VIEW_ZOOM_MEDIUM;
197
198 }
199
200 void wxWebViewIE::SetZoom(wxWebViewZoom zoom)
201 {
202 if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_LAYOUT)
203 SetIEOpticalZoom(zoom);
204 else if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_TEXT)
205 SetIETextZoom(zoom);
206 else
207 wxFAIL;
208 }
209
210 void wxWebViewIE::SetIETextZoom(wxWebViewZoom level)
211 {
212 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
213 //is 0 to 4 so the check is unnecessary, these match exactly with the
214 //enum values
215 VARIANT zoomVariant;
216 VariantInit (&zoomVariant);
217 V_VT(&zoomVariant) = VT_I4;
218 V_I4(&zoomVariant) = level;
219
220 HRESULT result = m_webBrowser->ExecWB(OLECMDID_ZOOM,
221 OLECMDEXECOPT_DONTPROMPTUSER,
222 &zoomVariant, NULL);
223 wxASSERT(result == S_OK);
224 }
225
226 wxWebViewZoom wxWebViewIE::GetIETextZoom()
227 {
228 VARIANT zoomVariant;
229 VariantInit (&zoomVariant);
230 V_VT(&zoomVariant) = VT_I4;
231
232 HRESULT result = m_webBrowser->ExecWB(OLECMDID_ZOOM,
233 OLECMDEXECOPT_DONTPROMPTUSER,
234 NULL, &zoomVariant);
235 wxASSERT(result == S_OK);
236
237 //We can safely cast here as we know that the range matches our enum
238 return static_cast<wxWebViewZoom>(V_I4(&zoomVariant));
239 }
240
241 void wxWebViewIE::SetIEOpticalZoom(wxWebViewZoom level)
242 {
243 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
244 //is 10 to 1000 so the check is unnecessary
245 VARIANT zoomVariant;
246 VariantInit (&zoomVariant);
247 V_VT(&zoomVariant) = VT_I4;
248
249 //We make a somewhat arbitray map here, taken from values used by webkit
250 switch(level)
251 {
252 case wxWEB_VIEW_ZOOM_TINY:
253 V_I4(&zoomVariant) = 60;
254 break;
255 case wxWEB_VIEW_ZOOM_SMALL:
256 V_I4(&zoomVariant) = 80;
257 break;
258 case wxWEB_VIEW_ZOOM_MEDIUM:
259 V_I4(&zoomVariant) = 100;
260 break;
261 case wxWEB_VIEW_ZOOM_LARGE:
262 V_I4(&zoomVariant) = 130;
263 break;
264 case wxWEB_VIEW_ZOOM_LARGEST:
265 V_I4(&zoomVariant) = 160;
266 break;
267 default:
268 wxFAIL;
269 }
270
271 HRESULT result = m_webBrowser->ExecWB((OLECMDID)OLECMDID_OPTICAL_ZOOM,
272 OLECMDEXECOPT_DODEFAULT,
273 &zoomVariant,
274 NULL);
275 wxASSERT(result == S_OK);
276 }
277
278 wxWebViewZoom wxWebViewIE::GetIEOpticalZoom()
279 {
280 VARIANT zoomVariant;
281 VariantInit (&zoomVariant);
282 V_VT(&zoomVariant) = VT_I4;
283
284 HRESULT result = m_webBrowser->ExecWB((OLECMDID)OLECMDID_OPTICAL_ZOOM,
285 OLECMDEXECOPT_DODEFAULT, NULL,
286 &zoomVariant);
287 wxASSERT(result == S_OK);
288
289 const int zoom = V_I4(&zoomVariant);
290
291 //We make a somewhat arbitray map here, taken from values used by webkit
292 if (zoom <= 65)
293 {
294 return wxWEB_VIEW_ZOOM_TINY;
295 }
296 else if (zoom > 65 && zoom <= 90)
297 {
298 return wxWEB_VIEW_ZOOM_SMALL;
299 }
300 else if (zoom > 90 && zoom <= 115)
301 {
302 return wxWEB_VIEW_ZOOM_MEDIUM;
303 }
304 else if (zoom > 115 && zoom <= 145)
305 {
306 return wxWEB_VIEW_ZOOM_LARGE;
307 }
308 else /*if (zoom > 145) */ //Using else removes a compiler warning
309 {
310 return wxWEB_VIEW_ZOOM_LARGEST;
311 }
312 }
313
314 void wxWebViewIE::SetZoomType(wxWebViewZoomType type)
315 {
316 m_zoomType = type;
317 }
318
319 wxWebViewZoomType wxWebViewIE::GetZoomType() const
320 {
321 return m_zoomType;
322 }
323
324 bool wxWebViewIE::CanSetZoomType(wxWebViewZoomType type) const
325 {
326 //IE 6 and below only support text zoom, so check the registry to see what
327 //version we actually have
328 wxRegKey key(wxRegKey::HKLM, "Software\\Microsoft\\Internet Explorer");
329 wxString value;
330 key.QueryValue("Version", value);
331
332 long version = wxAtoi(value.Left(1));
333 if(version <= 6 && type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT)
334 return false;
335 else
336 return true;
337 }
338
339 void wxWebViewIE::Print()
340 {
341 m_webBrowser->ExecWB(OLECMDID_PRINTPREVIEW,
342 OLECMDEXECOPT_DODEFAULT, NULL, NULL);
343 }
344
345 bool wxWebViewIE::CanGoBack()
346 {
347 if(m_historyEnabled)
348 return m_historyPosition > 0;
349 else
350 return false;
351 }
352
353 bool wxWebViewIE::CanGoForward()
354 {
355 if(m_historyEnabled)
356 return m_historyPosition != static_cast<int>(m_historyList.size()) - 1;
357 else
358 return false;
359 }
360
361 void wxWebViewIE::LoadHistoryItem(wxSharedPtr<wxWebHistoryItem> item)
362 {
363 int pos = -1;
364 for(unsigned int i = 0; i < m_historyList.size(); i++)
365 {
366 //We compare the actual pointers to find the correct item
367 if(m_historyList[i].get() == item.get())
368 pos = i;
369 }
370 wxASSERT_MSG(pos != static_cast<int>(m_historyList.size()),
371 "invalid history item");
372 m_historyLoadingFromList = true;
373 LoadUrl(item->GetUrl());
374 m_historyPosition = pos;
375 }
376
377 wxVector<wxSharedPtr<wxWebHistoryItem> > wxWebViewIE::GetBackwardHistory()
378 {
379 wxVector<wxSharedPtr<wxWebHistoryItem> > backhist;
380 //As we don't have std::copy or an iterator constructor in the wxwidgets
381 //native vector we construct it by hand
382 for(int i = 0; i < m_historyPosition; i++)
383 {
384 backhist.push_back(m_historyList[i]);
385 }
386 return backhist;
387 }
388
389 wxVector<wxSharedPtr<wxWebHistoryItem> > wxWebViewIE::GetForwardHistory()
390 {
391 wxVector<wxSharedPtr<wxWebHistoryItem> > forwardhist;
392 //As we don't have std::copy or an iterator constructor in the wxwidgets
393 //native vector we construct it by hand
394 for(int i = m_historyPosition + 1; i < static_cast<int>(m_historyList.size()); i++)
395 {
396 forwardhist.push_back(m_historyList[i]);
397 }
398 return forwardhist;
399 }
400
401 void wxWebViewIE::GoBack()
402 {
403 LoadHistoryItem(m_historyList[m_historyPosition - 1]);
404 }
405
406 void wxWebViewIE::GoForward()
407 {
408 LoadHistoryItem(m_historyList[m_historyPosition + 1]);
409 }
410
411 void wxWebViewIE::Stop()
412 {
413 m_ie.CallMethod("Stop");
414 }
415
416 void wxWebViewIE::ClearHistory()
417 {
418 m_historyList.clear();
419 m_historyPosition = -1;
420 }
421
422 void wxWebViewIE::EnableHistory(bool enable)
423 {
424 m_historyEnabled = enable;
425 m_historyList.clear();
426 m_historyPosition = -1;
427 }
428
429 void wxWebViewIE::Reload(wxWebViewReloadFlags flags)
430 {
431 VARIANTARG level;
432 VariantInit(&level);
433 V_VT(&level) = VT_I2;
434
435 switch(flags)
436 {
437 case wxWEB_VIEW_RELOAD_DEFAULT:
438 V_I2(&level) = REFRESH_NORMAL;
439 break;
440 case wxWEB_VIEW_RELOAD_NO_CACHE:
441 V_I2(&level) = REFRESH_COMPLETELY;
442 break;
443 default:
444 wxFAIL_MSG("Unexpected reload type");
445 }
446
447 m_webBrowser->Refresh2(&level);
448 }
449
450 bool wxWebViewIE::IsOfflineMode()
451 {
452 wxVariant out = m_ie.GetProperty("Offline");
453
454 wxASSERT(out.GetType() == "bool");
455
456 return out.GetBool();
457 }
458
459 void wxWebViewIE::SetOfflineMode(bool offline)
460 {
461 // FIXME: the wxWidgets docs do not really document what the return
462 // parameter of PutProperty is
463 const bool success = m_ie.PutProperty("Offline", (offline ?
464 VARIANT_TRUE :
465 VARIANT_FALSE));
466 wxASSERT(success);
467 }
468
469 bool wxWebViewIE::IsBusy()
470 {
471 if (m_isBusy) return true;
472
473 wxVariant out = m_ie.GetProperty("Busy");
474
475 wxASSERT(out.GetType() == "bool");
476
477 return out.GetBool();
478 }
479
480 wxString wxWebViewIE::GetCurrentURL()
481 {
482 wxVariant out = m_ie.GetProperty("LocationURL");
483
484 wxASSERT(out.GetType() == "string");
485 return out.GetString();
486 }
487
488 wxString wxWebViewIE::GetCurrentTitle()
489 {
490 IHTMLDocument2* document = GetDocument();
491 BSTR title;
492
493 document->get_nameProp(&title);
494 document->Release();
495 return wxString(title);
496 }
497
498 bool wxWebViewIE::CanCut()
499 {
500 return CanExecCommand("Cut");
501 }
502
503 bool wxWebViewIE::CanCopy()
504 {
505 return CanExecCommand("Copy");
506 }
507 bool wxWebViewIE::CanPaste()
508 {
509 return CanExecCommand("Paste");
510 }
511
512 void wxWebViewIE::Cut()
513 {
514 ExecCommand("Cut");
515 }
516
517 void wxWebViewIE::Copy()
518 {
519 ExecCommand("Copy");
520 }
521
522 void wxWebViewIE::Paste()
523 {
524 ExecCommand("Paste");
525 }
526
527 bool wxWebViewIE::CanUndo()
528 {
529 return CanExecCommand("Undo");
530 }
531 bool wxWebViewIE::CanRedo()
532 {
533 return CanExecCommand("Redo");
534 }
535
536 void wxWebViewIE::Undo()
537 {
538 ExecCommand("Undo");
539 }
540
541 void wxWebViewIE::Redo()
542 {
543 ExecCommand("Redo");
544 }
545
546 void wxWebViewIE::SetEditable(bool enable)
547 {
548 IHTMLDocument2* document = GetDocument();
549 if( enable )
550 document->put_designMode(SysAllocString(L"On"));
551 else
552 document->put_designMode(SysAllocString(L"Off"));
553
554 document->Release();
555 }
556
557 bool wxWebViewIE::IsEditable()
558 {
559 IHTMLDocument2* document = GetDocument();
560 BSTR mode;
561 document->get_designMode(&mode);
562 document->Release();
563 if(wxString(mode) == "On")
564 return true;
565 else
566 return false;
567 }
568
569 void wxWebViewIE::SelectAll()
570 {
571 ExecCommand("SelectAll");
572 }
573
574 bool wxWebViewIE::HasSelection()
575 {
576 IHTMLDocument2* document = GetDocument();
577 IHTMLSelectionObject* selection;
578 wxString sel;
579 HRESULT hr = document->get_selection(&selection);
580 if(SUCCEEDED(hr))
581 {
582 BSTR type;
583 selection->get_type(&type);
584 sel = wxString(type);
585 selection->Release();
586 }
587 document->Release();
588 return sel != "None";
589 }
590
591 void wxWebViewIE::DeleteSelection()
592 {
593 ExecCommand("Delete");
594 }
595
596 wxString wxWebViewIE::GetSelectedText()
597 {
598 IHTMLDocument2* document = GetDocument();
599 IHTMLSelectionObject* selection;
600 wxString selected;
601 HRESULT hr = document->get_selection(&selection);
602 if(SUCCEEDED(hr))
603 {
604 IDispatch* disrange;
605 hr = selection->createRange(&disrange);
606 if(SUCCEEDED(hr))
607 {
608 IHTMLTxtRange* range;
609 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
610 if(SUCCEEDED(hr))
611 {
612 BSTR text;
613 range->get_text(&text);
614 selected = wxString(text);
615 range->Release();
616 }
617 disrange->Release();
618 }
619 selection->Release();
620 }
621 document->Release();
622 return selected;
623 }
624
625 wxString wxWebViewIE::GetSelectedSource()
626 {
627 IHTMLDocument2* document = GetDocument();
628 IHTMLSelectionObject* selection;
629 wxString selected;
630 HRESULT hr = document->get_selection(&selection);
631 if(SUCCEEDED(hr))
632 {
633 IDispatch* disrange;
634 hr = selection->createRange(&disrange);
635 if(SUCCEEDED(hr))
636 {
637 IHTMLTxtRange* range;
638 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
639 if(SUCCEEDED(hr))
640 {
641 BSTR text;
642 range->get_htmlText(&text);
643 selected = wxString(text);
644 range->Release();
645 }
646 disrange->Release();
647 }
648 selection->Release();
649 }
650 document->Release();
651 return selected;
652 }
653
654 void wxWebViewIE::ClearSelection()
655 {
656 IHTMLDocument2* document = GetDocument();
657 IHTMLSelectionObject* selection;
658 wxString selected;
659 HRESULT hr = document->get_selection(&selection);
660 if(SUCCEEDED(hr))
661 {
662 selection->empty();
663 selection->Release();
664 }
665 document->Release();
666 }
667
668 wxString wxWebViewIE::GetPageText()
669 {
670 IHTMLDocument2* document = GetDocument();
671 wxString text;
672 IHTMLElement* body;
673 HRESULT hr = document->get_body(&body);
674 if(SUCCEEDED(hr))
675 {
676 BSTR out;
677 body->get_innerText(&out);
678 text = wxString(out);
679 body->Release();
680 }
681 document->Release();
682 return text;
683 }
684
685 void wxWebViewIE::RunScript(const wxString& javascript)
686 {
687 IHTMLDocument2* document = GetDocument();
688 IHTMLWindow2* window;
689 wxString language = "javascript";
690 HRESULT hr = document->get_parentWindow(&window);
691 if(SUCCEEDED(hr))
692 {
693 VARIANT level;
694 VariantInit(&level);
695 V_VT(&level) = VT_EMPTY;
696 window->execScript(SysAllocString(javascript), SysAllocString(language), &level);
697 }
698 document->Release();
699 }
700
701 bool wxWebViewIE::CanExecCommand(wxString command)
702 {
703 IHTMLDocument2* document = GetDocument();
704 VARIANT_BOOL enabled;
705
706 document->queryCommandEnabled(SysAllocString(command.wc_str()), &enabled);
707 document->Release();
708
709 return (enabled == VARIANT_TRUE);
710 }
711
712 void wxWebViewIE::ExecCommand(wxString command)
713 {
714 IHTMLDocument2* document = GetDocument();
715 document->execCommand(SysAllocString(command.wc_str()), VARIANT_FALSE, VARIANT(), NULL);
716 document->Release();
717 }
718
719 IHTMLDocument2* wxWebViewIE::GetDocument()
720 {
721 wxVariant variant = m_ie.GetProperty("Document");
722 IHTMLDocument2* document = (IHTMLDocument2*)variant.GetVoidPtr();
723
724 wxASSERT(document);
725
726 return document;
727 }
728
729 void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt)
730 {
731 if (m_webBrowser == NULL) return;
732
733 switch (evt.GetDispatchId())
734 {
735 case DISPID_BEFORENAVIGATE2:
736 {
737 m_isBusy = true;
738
739 wxString url = evt[1].GetString();
740 wxString target = evt[3].GetString();
741
742 wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,
743 GetId(), url, target, true);
744 event.SetEventObject(this);
745 HandleWindowEvent(event);
746
747 if (event.IsVetoed())
748 {
749 wxActiveXEventNativeMSW* nativeParams =
750 evt.GetNativeParameters();
751 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[0]) = VARIANT_TRUE;
752 }
753
754 // at this point, either the navigation event has been cancelled
755 // and we're not busy, either it was accepted and IWebBrowser2's
756 // Busy property will be true; so we don't need our override
757 // flag anymore.
758 m_isBusy = false;
759
760 break;
761 }
762
763 case DISPID_NAVIGATECOMPLETE2:
764 {
765 wxString url = evt[1].GetString();
766 // TODO: set target parameter if possible
767 wxString target = wxEmptyString;
768 wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
769 GetId(), url, target, false);
770 event.SetEventObject(this);
771 HandleWindowEvent(event);
772 break;
773 }
774
775 case DISPID_PROGRESSCHANGE:
776 {
777 // download progress
778 break;
779 }
780
781 case DISPID_DOCUMENTCOMPLETE:
782 {
783 //Only send a complete even if we are actually finished, this brings
784 //the event in to line with webkit
785 READYSTATE rs;
786 m_webBrowser->get_ReadyState( &rs );
787 if(rs != READYSTATE_COMPLETE)
788 break;
789
790 wxString url = evt[1].GetString();
791
792 //As we are complete we also add to the history list, but not if the
793 //page is not the main page, ie it is a subframe
794 if(m_historyEnabled && !m_historyLoadingFromList && url == GetCurrentURL())
795 {
796 //If we are not at the end of the list, then erase everything
797 //between us and the end before adding the new page
798 if(m_historyPosition != static_cast<int>(m_historyList.size()) - 1)
799 {
800 m_historyList.erase(m_historyList.begin() + m_historyPosition + 1,
801 m_historyList.end());
802 }
803 wxSharedPtr<wxWebHistoryItem> item(new wxWebHistoryItem(url, GetCurrentTitle()));
804 m_historyList.push_back(item);
805 m_historyPosition++;
806 }
807 //Reset as we are done now
808 m_historyLoadingFromList = false;
809 // TODO: set target parameter if possible
810 wxString target = wxEmptyString;
811 wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED, GetId(),
812 url, target, false);
813 event.SetEventObject(this);
814 HandleWindowEvent(event);
815 break;
816 }
817
818 case DISPID_STATUSTEXTCHANGE:
819 {
820 break;
821 }
822
823 case DISPID_TITLECHANGE:
824 {
825 break;
826 }
827
828 case DISPID_NAVIGATEERROR:
829 {
830 wxWebNavigationError errorType = wxWEB_NAV_ERR_OTHER;
831 wxString errorCode = "?";
832 switch (evt[3].GetLong())
833 {
834 case INET_E_INVALID_URL: // (0x800C0002L or -2146697214)
835 errorCode = "INET_E_INVALID_URL";
836 errorType = wxWEB_NAV_ERR_REQUEST;
837 break;
838 case INET_E_NO_SESSION: // (0x800C0003L or -2146697213)
839 errorCode = "INET_E_NO_SESSION";
840 errorType = wxWEB_NAV_ERR_CONNECTION;
841 break;
842 case INET_E_CANNOT_CONNECT: // (0x800C0004L or -2146697212)
843 errorCode = "INET_E_CANNOT_CONNECT";
844 errorType = wxWEB_NAV_ERR_CONNECTION;
845 break;
846 case INET_E_RESOURCE_NOT_FOUND: // (0x800C0005L or -2146697211)
847 errorCode = "INET_E_RESOURCE_NOT_FOUND";
848 errorType = wxWEB_NAV_ERR_NOT_FOUND;
849 break;
850 case INET_E_OBJECT_NOT_FOUND: // (0x800C0006L or -2146697210)
851 errorCode = "INET_E_OBJECT_NOT_FOUND";
852 errorType = wxWEB_NAV_ERR_NOT_FOUND;
853 break;
854 case INET_E_DATA_NOT_AVAILABLE: // (0x800C0007L or -2146697209)
855 errorCode = "INET_E_DATA_NOT_AVAILABLE";
856 errorType = wxWEB_NAV_ERR_NOT_FOUND;
857 break;
858 case INET_E_DOWNLOAD_FAILURE: // (0x800C0008L or -2146697208)
859 errorCode = "INET_E_DOWNLOAD_FAILURE";
860 errorType = wxWEB_NAV_ERR_CONNECTION;
861 break;
862 case INET_E_AUTHENTICATION_REQUIRED: // (0x800C0009L or -2146697207)
863 errorCode = "INET_E_AUTHENTICATION_REQUIRED";
864 errorType = wxWEB_NAV_ERR_AUTH;
865 break;
866 case INET_E_NO_VALID_MEDIA: // (0x800C000AL or -2146697206)
867 errorCode = "INET_E_NO_VALID_MEDIA";
868 errorType = wxWEB_NAV_ERR_REQUEST;
869 break;
870 case INET_E_CONNECTION_TIMEOUT: // (0x800C000BL or -2146697205)
871 errorCode = "INET_E_CONNECTION_TIMEOUT";
872 errorType = wxWEB_NAV_ERR_CONNECTION;
873 break;
874 case INET_E_INVALID_REQUEST: // (0x800C000CL or -2146697204)
875 errorCode = "INET_E_INVALID_REQUEST";
876 errorType = wxWEB_NAV_ERR_REQUEST;
877 break;
878 case INET_E_UNKNOWN_PROTOCOL: // (0x800C000DL or -2146697203)
879 errorCode = "INET_E_UNKNOWN_PROTOCOL";
880 errorType = wxWEB_NAV_ERR_REQUEST;
881 break;
882 case INET_E_SECURITY_PROBLEM: // (0x800C000EL or -2146697202)
883 errorCode = "INET_E_SECURITY_PROBLEM";
884 errorType = wxWEB_NAV_ERR_SECURITY;
885 break;
886 case INET_E_CANNOT_LOAD_DATA: // (0x800C000FL or -2146697201)
887 errorCode = "INET_E_CANNOT_LOAD_DATA";
888 errorType = wxWEB_NAV_ERR_OTHER;
889 break;
890 case INET_E_CANNOT_INSTANTIATE_OBJECT:
891 // CoCreateInstance will return an error code if this happens,
892 // we'll handle this above.
893 return;
894 break;
895 case INET_E_REDIRECT_FAILED: // (0x800C0014L or -2146697196)
896 errorCode = "INET_E_REDIRECT_FAILED";
897 errorType = wxWEB_NAV_ERR_OTHER;
898 break;
899 case INET_E_REDIRECT_TO_DIR: // (0x800C0015L or -2146697195)
900 errorCode = "INET_E_REDIRECT_TO_DIR";
901 errorType = wxWEB_NAV_ERR_REQUEST;
902 break;
903 case INET_E_CANNOT_LOCK_REQUEST: // (0x800C0016L or -2146697194)
904 errorCode = "INET_E_CANNOT_LOCK_REQUEST";
905 errorType = wxWEB_NAV_ERR_OTHER;
906 break;
907 case INET_E_USE_EXTEND_BINDING: // (0x800C0017L or -2146697193)
908 errorCode = "INET_E_USE_EXTEND_BINDING";
909 errorType = wxWEB_NAV_ERR_OTHER;
910 break;
911 case INET_E_TERMINATED_BIND: // (0x800C0018L or -2146697192)
912 errorCode = "INET_E_TERMINATED_BIND";
913 errorType = wxWEB_NAV_ERR_OTHER;
914 break;
915 case INET_E_INVALID_CERTIFICATE: // (0x800C0019L or -2146697191)
916 errorCode = "INET_E_INVALID_CERTIFICATE";
917 errorType = wxWEB_NAV_ERR_CERTIFICATE;
918 break;
919 case INET_E_CODE_DOWNLOAD_DECLINED: // (0x800C0100L or -2146696960)
920 errorCode = "INET_E_CODE_DOWNLOAD_DECLINED";
921 errorType = wxWEB_NAV_ERR_USER_CANCELLED;
922 break;
923 case INET_E_RESULT_DISPATCHED: // (0x800C0200L or -2146696704)
924 // cancel request cancelled...
925 errorCode = "INET_E_RESULT_DISPATCHED";
926 errorType = wxWEB_NAV_ERR_OTHER;
927 break;
928 case INET_E_CANNOT_REPLACE_SFP_FILE: // (0x800C0300L or -2146696448)
929 errorCode = "INET_E_CANNOT_REPLACE_SFP_FILE";
930 errorType = wxWEB_NAV_ERR_SECURITY;
931 break;
932 case INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY:
933 errorCode = "INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY";
934 errorType = wxWEB_NAV_ERR_SECURITY;
935 break;
936 case INET_E_CODE_INSTALL_SUPPRESSED:
937 errorCode = "INET_E_CODE_INSTALL_SUPPRESSED";
938 errorType = wxWEB_NAV_ERR_SECURITY;
939 break;
940 }
941
942 wxString url = evt[1].GetString();
943 wxString target = evt[2].GetString();
944 wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR, GetId(),
945 url, target, false);
946 event.SetEventObject(this);
947 event.SetInt(errorType);
948 event.SetString(errorCode);
949 HandleWindowEvent(event);
950 break;
951 }
952
953 case DISPID_COMMANDSTATECHANGE:
954 {
955 long commandId = evt[0].GetLong();
956 bool enable = evt[1].GetBool();
957 if (commandId == CSC_NAVIGATEBACK)
958 {
959 m_canNavigateBack = enable;
960 }
961 else if (commandId == CSC_NAVIGATEFORWARD)
962 {
963 m_canNavigateForward = enable;
964 }
965 break;
966 }
967 case DISPID_NEWWINDOW3:
968 {
969 wxString url = evt[4].GetString();
970
971 wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW,
972 GetId(), url, wxEmptyString, true);
973 event.SetEventObject(this);
974 HandleWindowEvent(event);
975
976 //If we veto the event then we cancel the new window
977 if (event.IsVetoed())
978 {
979 wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters();
980 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[3]) = VARIANT_TRUE;
981 }
982 break;
983 }
984 }
985
986 evt.Skip();
987 }
988
989 VirtualProtocol::VirtualProtocol()
990 {
991 m_refCount = 0;
992 m_file = NULL;
993 m_fileSys = new wxFileSystem;
994 }
995
996 VirtualProtocol::~VirtualProtocol()
997 {
998 wxDELETE(m_fileSys);
999 }
1000
1001 ULONG VirtualProtocol::AddRef()
1002 {
1003 m_refCount++;
1004 return m_refCount;
1005 }
1006
1007 HRESULT VirtualProtocol::QueryInterface(REFIID riid, void **ppvObject)
1008 {
1009 if ((riid == IID_IUnknown) || (riid == IID_IInternetProtocol)
1010 || (riid == IID_IInternetProtocolRoot))
1011 {
1012 *ppvObject = this;
1013 AddRef();
1014 return S_OK;
1015 }
1016 else
1017 {
1018 *ppvObject = NULL;
1019 return E_POINTER;
1020 }
1021 }
1022
1023 ULONG VirtualProtocol::Release()
1024 {
1025 m_refCount--;
1026 if (m_refCount > 0)
1027 {
1028 return m_refCount;
1029 }
1030 else
1031 {
1032 delete this;
1033 return 0;
1034 }
1035 }
1036
1037 HRESULT VirtualProtocol::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink,
1038 IInternetBindInfo *pOIBindInfo, DWORD grfPI,
1039 HANDLE_PTR dwReserved)
1040 {
1041 m_protocolSink = pOIProtSink;
1042 //We have to clean up incoming paths from the webview control as they are
1043 //not properly escaped, see also the comment in filesys.cpp line 668
1044 wxString path = wxString(szUrl).BeforeFirst(':') + ":" +
1045 EscapeFileNameCharsInURL(wxString(szUrl).AfterFirst(':'));
1046 path.Replace("///", "/");
1047 m_file = m_fileSys->OpenFile(path);
1048
1049 if(!m_file)
1050 return INET_E_RESOURCE_NOT_FOUND;
1051
1052 //We return the stream length for current and total size as we can always
1053 //read the whole file from the stream
1054 m_protocolSink->ReportData(BSCF_FIRSTDATANOTIFICATION |
1055 BSCF_DATAFULLYAVAILABLE |
1056 BSCF_LASTDATANOTIFICATION,
1057 m_file->GetStream()->GetLength(),
1058 m_file->GetStream()->GetLength());
1059 return S_OK;
1060 }
1061
1062 HRESULT VirtualProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
1063 {
1064 //If the file is null we return false to indicte it is finished
1065 if(!m_file)
1066 return S_FALSE;
1067
1068 wxStreamError err = m_file->GetStream()->Read(pv, cb).GetLastError();
1069 *pcbRead = m_file->GetStream()->LastRead();
1070
1071 if(err == wxSTREAM_NO_ERROR)
1072 {
1073 if(*pcbRead < cb)
1074 {
1075 wxDELETE(m_file);
1076 m_protocolSink->ReportResult(S_OK, 0, NULL);
1077 }
1078 //As we are not eof there is more data
1079 return S_OK;
1080 }
1081 else if(err == wxSTREAM_EOF)
1082 {
1083 wxDELETE(m_file);
1084 m_protocolSink->ReportResult(S_OK, 0, NULL);
1085 //We are eof and so finished
1086 return S_OK;
1087 }
1088 else if(err == wxSTREAM_READ_ERROR)
1089 {
1090 wxDELETE(m_file);
1091 return INET_E_DOWNLOAD_FAILURE;
1092 }
1093 }
1094
1095 HRESULT ClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
1096 void ** ppvObject)
1097 {
1098 if (pUnkOuter)
1099 return CLASS_E_NOAGGREGATION;
1100 VirtualProtocol* vp = new VirtualProtocol;
1101 vp->AddRef();
1102 HRESULT hr = vp->QueryInterface(riid, ppvObject);
1103 vp->Release();
1104 return hr;
1105
1106 }
1107
1108 STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
1109 {
1110 return S_OK;
1111
1112 }
1113
1114 ULONG ClassFactory::AddRef(void)
1115 {
1116 m_refCount++;
1117 return m_refCount;
1118 }
1119
1120 HRESULT ClassFactory::QueryInterface(REFIID riid, void **ppvObject)
1121 {
1122 if ((riid == IID_IUnknown) || (riid == IID_IClassFactory))
1123 {
1124 *ppvObject = this;
1125 AddRef();
1126 return S_OK;
1127 }
1128 else
1129 {
1130 *ppvObject = NULL;
1131 return E_POINTER;
1132 }
1133
1134 }
1135
1136 ULONG ClassFactory::Release(void)
1137 {
1138 m_refCount--;
1139 if (m_refCount > 0)
1140 {
1141 return m_refCount;
1142 }
1143 else
1144 {
1145 delete this;
1146 return 0;
1147 }
1148
1149 }
1150
1151 #endif