X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/617227c3094486c88b74d8133134a8049b0f0119..74a8f67d96591cec101def2a7d47c64072aff7fd:/src/msw/webview_ie.cpp?ds=inline diff --git a/src/msw/webview_ie.cpp b/src/msw/webview_ie.cpp index 9451961d8b..92edb4ecd5 100644 --- a/src/msw/webview_ie.cpp +++ b/src/msw/webview_ie.cpp @@ -3,7 +3,7 @@ // Purpose: wxMSW wxWebViewIE class implementation for web view component // Author: Marianne Gagnon // Id: $Id$ -// Copyright: (c) 2010 Marianne Gagnon, Steven Lamerton +// Copyright: (c) 2010 Marianne Gagnon, 2011 Steven Lamerton // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -23,52 +23,14 @@ #include #include #include +#include "wx/msw/registry.h" +#include "wx/msw/missing.h" +#include "wx/filesys.h" -// Various definitions are missing from mingw -#ifdef __MINGW32__ -typedef enum CommandStateChangeConstants { - CSC_UPDATECOMMANDS = (int) 0xFFFFFFFF, - CSC_NAVIGATEFORWARD = 0x1, - CSC_NAVIGATEBACK = 0x2 -} CommandStateChangeConstants; - -#define DISPID_COMMANDSTATECHANGE 105 -#define DISPID_NAVIGATECOMPLETE2 252 -#define DISPID_NAVIGATEERROR 271 -#define DISPID_NEWWINDOW3 273 -#define OLECMDID_OPTICAL_ZOOM 63 -#define INET_E_ERROR_FIRST 0x800C0002L -#define INET_E_INVALID_URL 0x800C0002L -#define INET_E_NO_SESSION 0x800C0003L -#define INET_E_CANNOT_CONNECT 0x800C0004L -#define INET_E_RESOURCE_NOT_FOUND 0x800C0005L -#define INET_E_OBJECT_NOT_FOUND 0x800C0006L -#define INET_E_DATA_NOT_AVAILABLE 0x800C0007L -#define INET_E_DOWNLOAD_FAILURE 0x800C0008L -#define INET_E_AUTHENTICATION_REQUIRED 0x800C0009L -#define INET_E_NO_VALID_MEDIA 0x800C000AL -#define INET_E_CONNECTION_TIMEOUT 0x800C000BL -#define INET_E_INVALID_REQUEST 0x800C000CL -#define INET_E_UNKNOWN_PROTOCOL 0x800C000DL -#define INET_E_SECURITY_PROBLEM 0x800C000EL -#define INET_E_CANNOT_LOAD_DATA 0x800C000FL -#define INET_E_CANNOT_INSTANTIATE_OBJECT 0x800C0010L -#define INET_E_QUERYOPTION_UNKNOWN 0x800C0013L -#define INET_E_REDIRECT_FAILED 0x800C0014L -#define INET_E_REDIRECT_TO_DIR 0x800C0015L -#define INET_E_CANNOT_LOCK_REQUEST 0x800C0016L -#define INET_E_USE_EXTEND_BINDING 0x800C0017L -#define INET_E_TERMINATED_BIND 0x800C0018L -#define INET_E_INVALID_CERTIFICATE 0x800C0019L -#define INET_E_CODE_DOWNLOAD_DECLINED 0x800C0100L -#define INET_E_RESULT_DISPATCHED 0x800C0200L -#define INET_E_CANNOT_REPLACE_SFP_FILE 0x800C0300L -#define INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY 0x800C0500L -#define INET_E_CODE_INSTALL_SUPPRESSED 0x800C0400L - -#define REFRESH_NORMAL 0 -#define REFRESH_COMPLETELY 3 -#endif +wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewIE, wxWebView); + +//We link to urlmon as it is required for CoInternetGetSession +#pragma comment(lib, "urlmon") BEGIN_EVENT_TABLE(wxWebViewIE, wxControl) EVT_ACTIVEX(wxID_ANY, wxWebViewIE::onActiveXEvent) @@ -90,12 +52,11 @@ bool wxWebViewIE::Create(wxWindow* parent, } m_webBrowser = NULL; - m_canNavigateBack = false; - m_canNavigateForward = false; m_isBusy = false; m_historyLoadingFromList = false; m_historyEnabled = true; m_historyPosition = -1; + m_zoomType = wxWEB_VIEW_ZOOM_TYPE_TEXT; if (::CoCreateInstance(CLSID_WebBrowser, NULL, CLSCTX_INPROC_SERVER, // CLSCTX_INPROC, @@ -109,37 +70,23 @@ bool wxWebViewIE::Create(wxWindow* parent, m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE); m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE); - //m_webBrowser->put_Silent(VARIANT_FALSE); m_container = new wxActiveXContainer(this, IID_IWebBrowser2, m_webBrowser); SetBackgroundStyle(wxBG_STYLE_PAINT); SetDoubleBuffered(true); - LoadUrl(url); + LoadURL(url); return true; } -void wxWebViewIE::LoadUrl(const wxString& url) +void wxWebViewIE::LoadURL(const wxString& url) { - wxVariant out = m_ie.CallMethod("Navigate", (BSTR) url.wc_str(), - NULL, NULL, NULL, NULL); - - // FIXME: why is out value null?? - //(HRESULT)(out.GetLong()) == S_OK; + m_ie.CallMethod("Navigate", (BSTR) url.wc_str(), NULL, NULL, NULL, NULL); } void wxWebViewIE::SetPage(const wxString& html, const wxString& baseUrl) { - LoadUrl("about:blank"); - - // Let the wx events generated for navigation events be processed, so - // that the underlying IE component completes its Document object. - // FIXME: calling wxYield is not elegant nor very reliable probably - wxYield(); - - // TODO: consider the "baseUrl" parameter if possible - // TODO: consider encoding BSTR bstr = SysAllocString(html.wc_str()); // Creates a new one-dimensional array @@ -147,16 +94,30 @@ void wxWebViewIE::SetPage(const wxString& html, const wxString& baseUrl) if (psaStrings != NULL) { VARIANT *param; + HRESULT hr = SafeArrayAccessData(psaStrings, (LPVOID*)¶m); param->vt = VT_BSTR; param->bstrVal = bstr; - hr = SafeArrayUnaccessData(psaStrings); + IHTMLDocument2* document = GetDocument(); document->write(psaStrings); + document->Release(); // SafeArrayDestroy calls SysFreeString for each BSTR SafeArrayDestroy(psaStrings); + + //We send the events when we are done to mimic webkit + //Navigated event + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED, + GetId(), baseUrl, ""); + event.SetEventObject(this); + HandleWindowEvent(event); + + //Document complete event + event.SetEventType(wxEVT_COMMAND_WEB_VIEW_LOADED); + event.SetEventObject(this); + HandleWindowEvent(event); } else { @@ -165,86 +126,59 @@ void wxWebViewIE::SetPage(const wxString& html, const wxString& baseUrl) } -wxString wxWebViewIE::GetPageSource() +wxString wxWebViewIE::GetPageSource() const { IHTMLDocument2* document = GetDocument(); IHTMLElement *bodyTag = NULL; IHTMLElement *htmlTag = NULL; - document->get_body(&bodyTag); - wxASSERT(bodyTag != NULL); + wxString source; + HRESULT hr = document->get_body(&bodyTag); + if(SUCCEEDED(hr)) + { + hr = bodyTag->get_parentElement(&htmlTag); + if(SUCCEEDED(hr)) + { + BSTR bstr; + htmlTag->get_outerHTML(&bstr); + source = wxString(bstr); + htmlTag->Release(); + } + bodyTag->Release(); + } document->Release(); - bodyTag->get_parentElement(&htmlTag); - wxASSERT(htmlTag != NULL); - - BSTR bstr; - htmlTag->get_outerHTML(&bstr); - - bodyTag->Release(); - htmlTag->Release(); - - //wxMessageBox(wxString(bstr)); - - // TODO: check encoding - return wxString(bstr); + return source; } -// FIXME? retrieve OLECMDID_GETZOOMRANGE instead of hardcoding range 0-4 -wxWebViewZoom wxWebViewIE::GetZoom() +wxWebViewZoom wxWebViewIE::GetZoom() const { - const int zoom = GetIETextZoom(); + if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_LAYOUT) + return GetIEOpticalZoom(); + else if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_TEXT) + return GetIETextZoom(); + else + wxFAIL; + + //Dummy return to stop compiler warnings + return wxWEB_VIEW_ZOOM_MEDIUM; - switch (zoom) - { - case 0: - return wxWEB_VIEW_ZOOM_TINY; - break; - case 1: - return wxWEB_VIEW_ZOOM_SMALL; - break; - case 2: - return wxWEB_VIEW_ZOOM_MEDIUM; - break; - case 3: - return wxWEB_VIEW_ZOOM_LARGE; - break; - case 4: - return wxWEB_VIEW_ZOOM_LARGEST; - break; - default: - wxASSERT(false); - return wxWEB_VIEW_ZOOM_MEDIUM; - } } + void wxWebViewIE::SetZoom(wxWebViewZoom zoom) { - // I know I could cast from enum to int since wxWebViewZoom happens to - // match with IE's zoom levels, but I don't like doing that, what if enum - // values change... - switch (zoom) - { - case wxWEB_VIEW_ZOOM_TINY: - SetIETextZoom(0); - break; - case wxWEB_VIEW_ZOOM_SMALL: - SetIETextZoom(1); - break; - case wxWEB_VIEW_ZOOM_MEDIUM: - SetIETextZoom(2); - break; - case wxWEB_VIEW_ZOOM_LARGE: - SetIETextZoom(3); - break; - case wxWEB_VIEW_ZOOM_LARGEST: - SetIETextZoom(4); - break; - default: - wxASSERT(false); - } + if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_LAYOUT) + SetIEOpticalZoom(zoom); + else if(m_zoomType == wxWEB_VIEW_ZOOM_TYPE_TEXT) + SetIETextZoom(zoom); + else + wxFAIL; } -void wxWebViewIE::SetIETextZoom(int level) +void wxWebViewIE::SetIETextZoom(wxWebViewZoom level) { + //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range + //is 0 to 4 so the check is unnecessary, these match exactly with the + //enum values VARIANT zoomVariant; VariantInit (&zoomVariant); V_VT(&zoomVariant) = VT_I4; @@ -253,87 +187,120 @@ void wxWebViewIE::SetIETextZoom(int level) HRESULT result = m_webBrowser->ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &zoomVariant, NULL); - wxASSERT (result == S_OK); - - VariantClear (&zoomVariant); + wxASSERT(result == S_OK); } -int wxWebViewIE::GetIETextZoom() +wxWebViewZoom wxWebViewIE::GetIETextZoom() const { VARIANT zoomVariant; VariantInit (&zoomVariant); V_VT(&zoomVariant) = VT_I4; - V_I4(&zoomVariant) = 4; HRESULT result = m_webBrowser->ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, NULL, &zoomVariant); - wxASSERT (result == S_OK); + wxASSERT(result == S_OK); - int zoom = V_I4(&zoomVariant); - // wxMessageBox(wxString::Format("Zoom : %i", zoom)); - VariantClear (&zoomVariant); - - return zoom; + //We can safely cast here as we know that the range matches our enum + return static_cast(V_I4(&zoomVariant)); } -void wxWebViewIE::SetIEOpticalZoom(float zoom) +void wxWebViewIE::SetIEOpticalZoom(wxWebViewZoom level) { - // TODO: add support for optical zoom (IE7+ only) - - // TODO: get range from OLECMDID_OPTICAL_GETZOOMRANGE instead of hardcoding? - wxASSERT(zoom >= 10.0f); - wxASSERT(zoom <= 1000.0f); - + //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range + //is 10 to 1000 so the check is unnecessary VARIANT zoomVariant; VariantInit (&zoomVariant); V_VT(&zoomVariant) = VT_I4; - V_I4(&zoomVariant) = (zoom * 100.0f); + + //We make a somewhat arbitray map here, taken from values used by webkit + switch(level) + { + case wxWEB_VIEW_ZOOM_TINY: + V_I4(&zoomVariant) = 60; + break; + case wxWEB_VIEW_ZOOM_SMALL: + V_I4(&zoomVariant) = 80; + break; + case wxWEB_VIEW_ZOOM_MEDIUM: + V_I4(&zoomVariant) = 100; + break; + case wxWEB_VIEW_ZOOM_LARGE: + V_I4(&zoomVariant) = 130; + break; + case wxWEB_VIEW_ZOOM_LARGEST: + V_I4(&zoomVariant) = 160; + break; + default: + wxFAIL; + } HRESULT result = m_webBrowser->ExecWB((OLECMDID)OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DODEFAULT, &zoomVariant, NULL); - wxASSERT (result == S_OK); + wxASSERT(result == S_OK); } -float wxWebViewIE::GetIEOpticalZoom() +wxWebViewZoom wxWebViewIE::GetIEOpticalZoom() const { - // TODO: add support for optical zoom (IE7+ only) - VARIANT zoomVariant; VariantInit (&zoomVariant); V_VT(&zoomVariant) = VT_I4; - V_I4(&zoomVariant) = -1; HRESULT result = m_webBrowser->ExecWB((OLECMDID)OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DODEFAULT, NULL, &zoomVariant); - wxASSERT (result == S_OK); + wxASSERT(result == S_OK); const int zoom = V_I4(&zoomVariant); - VariantClear (&zoomVariant); - return zoom / 100.0f; + //We make a somewhat arbitray map here, taken from values used by webkit + if (zoom <= 65) + { + return wxWEB_VIEW_ZOOM_TINY; + } + else if (zoom > 65 && zoom <= 90) + { + return wxWEB_VIEW_ZOOM_SMALL; + } + else if (zoom > 90 && zoom <= 115) + { + return wxWEB_VIEW_ZOOM_MEDIUM; + } + else if (zoom > 115 && zoom <= 145) + { + return wxWEB_VIEW_ZOOM_LARGE; + } + else /*if (zoom > 145) */ //Using else removes a compiler warning + { + return wxWEB_VIEW_ZOOM_LARGEST; + } } -void wxWebViewIE::SetZoomType(wxWebViewZoomType) +void wxWebViewIE::SetZoomType(wxWebViewZoomType type) { - // TODO: add support for optical zoom (IE7+ only) - wxASSERT(false); + m_zoomType = type; } wxWebViewZoomType wxWebViewIE::GetZoomType() const { - // TODO: add support for optical zoom (IE7+ only) - return wxWEB_VIEW_ZOOM_TYPE_TEXT; + return m_zoomType; } -bool wxWebViewIE::CanSetZoomType(wxWebViewZoomType) const +bool wxWebViewIE::CanSetZoomType(wxWebViewZoomType type) const { - // both are supported - // TODO: IE6 only supports text zoom, check if it's IE6 first - return true; + //IE 6 and below only support text zoom, so check the registry to see what + //version we actually have + wxRegKey key(wxRegKey::HKLM, "Software\\Microsoft\\Internet Explorer"); + wxString value; + key.QueryValue("Version", value); + + long version = wxAtoi(value.Left(1)); + if(version <= 6 && type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT) + return false; + else + return true; } void wxWebViewIE::Print() @@ -342,7 +309,7 @@ void wxWebViewIE::Print() OLECMDEXECOPT_DODEFAULT, NULL, NULL); } -bool wxWebViewIE::CanGoBack() +bool wxWebViewIE::CanGoBack() const { if(m_historyEnabled) return m_historyPosition > 0; @@ -350,15 +317,15 @@ bool wxWebViewIE::CanGoBack() return false; } -bool wxWebViewIE::CanGoForward() +bool wxWebViewIE::CanGoForward() const { if(m_historyEnabled) - return m_historyPosition != m_historyList.size() - 1; + return m_historyPosition != static_cast(m_historyList.size()) - 1; else return false; } -void wxWebViewIE::LoadHistoryItem(wxSharedPtr item) +void wxWebViewIE::LoadHistoryItem(wxSharedPtr item) { int pos = -1; for(unsigned int i = 0; i < m_historyList.size(); i++) @@ -367,15 +334,16 @@ void wxWebViewIE::LoadHistoryItem(wxSharedPtr item) if(m_historyList[i].get() == item.get()) pos = i; } - wxASSERT_MSG(pos != m_historyList.size(), "invalid history item"); + wxASSERT_MSG(pos != static_cast(m_historyList.size()), + "invalid history item"); m_historyLoadingFromList = true; - LoadUrl(item->GetUrl()); + LoadURL(item->GetUrl()); m_historyPosition = pos; } -wxVector > wxWebViewIE::GetBackwardHistory() +wxVector > wxWebViewIE::GetBackwardHistory() { - wxVector > backhist; + wxVector > backhist; //As we don't have std::copy or an iterator constructor in the wxwidgets //native vector we construct it by hand for(int i = 0; i < m_historyPosition; i++) @@ -385,12 +353,12 @@ wxVector > wxWebViewIE::GetBackwardHistory() return backhist; } -wxVector > wxWebViewIE::GetForwardHistory() +wxVector > wxWebViewIE::GetForwardHistory() { - wxVector > forwardhist; + wxVector > forwardhist; //As we don't have std::copy or an iterator constructor in the wxwidgets //native vector we construct it by hand - for(int i = m_historyPosition + 1; i < m_historyList.size(); i++) + for(int i = m_historyPosition + 1; i < static_cast(m_historyList.size()); i++) { forwardhist.push_back(m_historyList[i]); } @@ -409,10 +377,7 @@ void wxWebViewIE::GoForward() void wxWebViewIE::Stop() { - wxVariant out = m_ie.CallMethod("Stop"); - - // FIXME: why is out value null?? - //return (HRESULT)(out.GetLong()) == S_OK; + m_ie.CallMethod("Stop"); } void wxWebViewIE::ClearHistory() @@ -468,8 +433,8 @@ void wxWebViewIE::SetOfflineMode(bool offline) wxASSERT(success); } -bool wxWebViewIE::IsBusy() -{ +bool wxWebViewIE::IsBusy() const +{ if (m_isBusy) return true; wxVariant out = m_ie.GetProperty("Busy"); @@ -479,7 +444,7 @@ bool wxWebViewIE::IsBusy() return out.GetBool(); } -wxString wxWebViewIE::GetCurrentURL() +wxString wxWebViewIE::GetCurrentURL() const { wxVariant out = m_ie.GetProperty("LocationURL"); @@ -487,25 +452,26 @@ wxString wxWebViewIE::GetCurrentURL() return out.GetString(); } -wxString wxWebViewIE::GetCurrentTitle() +wxString wxWebViewIE::GetCurrentTitle() const { IHTMLDocument2* document = GetDocument(); - BSTR title; + document->get_nameProp(&title); + document->Release(); return wxString(title); } -bool wxWebViewIE::CanCut() +bool wxWebViewIE::CanCut() const { return CanExecCommand("Cut"); } -bool wxWebViewIE::CanCopy() +bool wxWebViewIE::CanCopy() const { return CanExecCommand("Copy"); } -bool wxWebViewIE::CanPaste() +bool wxWebViewIE::CanPaste() const { return CanExecCommand("Paste"); } @@ -525,11 +491,11 @@ void wxWebViewIE::Paste() ExecCommand("Paste"); } -bool wxWebViewIE::CanUndo() +bool wxWebViewIE::CanUndo() const { return CanExecCommand("Undo"); } -bool wxWebViewIE::CanRedo() +bool wxWebViewIE::CanRedo() const { return CanExecCommand("Redo"); } @@ -544,12 +510,184 @@ void wxWebViewIE::Redo() ExecCommand("Redo"); } -bool wxWebViewIE::CanExecCommand(wxString command) +void wxWebViewIE::SetEditable(bool enable) +{ + IHTMLDocument2* document = GetDocument(); + if( enable ) + document->put_designMode(SysAllocString(L"On")); + else + document->put_designMode(SysAllocString(L"Off")); + + document->Release(); +} + +bool wxWebViewIE::IsEditable() const +{ + IHTMLDocument2* document = GetDocument(); + BSTR mode; + document->get_designMode(&mode); + document->Release(); + if(wxString(mode) == "On") + return true; + else + return false; +} + +void wxWebViewIE::SelectAll() +{ + ExecCommand("SelectAll"); +} + +bool wxWebViewIE::HasSelection() const +{ + IHTMLDocument2* document = GetDocument(); + IHTMLSelectionObject* selection; + wxString sel; + HRESULT hr = document->get_selection(&selection); + if(SUCCEEDED(hr)) + { + BSTR type; + selection->get_type(&type); + sel = wxString(type); + selection->Release(); + } + document->Release(); + return sel != "None"; +} + +void wxWebViewIE::DeleteSelection() +{ + ExecCommand("Delete"); +} + +wxString wxWebViewIE::GetSelectedText() const +{ + IHTMLDocument2* document = GetDocument(); + IHTMLSelectionObject* selection; + wxString selected; + HRESULT hr = document->get_selection(&selection); + if(SUCCEEDED(hr)) + { + IDispatch* disrange; + hr = selection->createRange(&disrange); + if(SUCCEEDED(hr)) + { + IHTMLTxtRange* range; + hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range); + if(SUCCEEDED(hr)) + { + BSTR text; + range->get_text(&text); + selected = wxString(text); + range->Release(); + } + disrange->Release(); + } + selection->Release(); + } + document->Release(); + return selected; +} + +wxString wxWebViewIE::GetSelectedSource() const +{ + IHTMLDocument2* document = GetDocument(); + IHTMLSelectionObject* selection; + wxString selected; + HRESULT hr = document->get_selection(&selection); + if(SUCCEEDED(hr)) + { + IDispatch* disrange; + hr = selection->createRange(&disrange); + if(SUCCEEDED(hr)) + { + IHTMLTxtRange* range; + hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range); + if(SUCCEEDED(hr)) + { + BSTR text; + range->get_htmlText(&text); + selected = wxString(text); + range->Release(); + } + disrange->Release(); + } + selection->Release(); + } + document->Release(); + return selected; +} + +void wxWebViewIE::ClearSelection() { IHTMLDocument2* document = GetDocument(); + IHTMLSelectionObject* selection; + wxString selected; + HRESULT hr = document->get_selection(&selection); + if(SUCCEEDED(hr)) + { + selection->empty(); + selection->Release(); + } + document->Release(); +} +wxString wxWebViewIE::GetPageText() const +{ + IHTMLDocument2* document = GetDocument(); + wxString text; + IHTMLElement* body; + HRESULT hr = document->get_body(&body); + if(SUCCEEDED(hr)) + { + BSTR out; + body->get_innerText(&out); + text = wxString(out); + body->Release(); + } + document->Release(); + return text; +} + +void wxWebViewIE::RunScript(const wxString& javascript) +{ + IHTMLDocument2* document = GetDocument(); + IHTMLWindow2* window; + wxString language = "javascript"; + HRESULT hr = document->get_parentWindow(&window); + if(SUCCEEDED(hr)) + { + VARIANT level; + VariantInit(&level); + V_VT(&level) = VT_EMPTY; + window->execScript(SysAllocString(javascript), SysAllocString(language), &level); + } + document->Release(); +} + +void wxWebViewIE::RegisterHandler(wxSharedPtr handler) +{ + ClassFactory* cf = new ClassFactory(handler); + IInternetSession* session; + if(FAILED(CoInternetGetSession(0, &session, 0))) + { + wxFAIL_MSG("Could not retrive internet session"); + } + + HRESULT hr = session->RegisterNameSpace(cf, CLSID_FileProtocol, handler->GetName(), 0, NULL, 0); + if(FAILED(hr)) + { + wxFAIL_MSG("Could not register protocol"); + } +} + +bool wxWebViewIE::CanExecCommand(wxString command) const +{ + IHTMLDocument2* document = GetDocument(); VARIANT_BOOL enabled; + document->queryCommandEnabled(SysAllocString(command.wc_str()), &enabled); + document->Release(); return (enabled == VARIANT_TRUE); } @@ -558,9 +696,10 @@ void wxWebViewIE::ExecCommand(wxString command) { IHTMLDocument2* document = GetDocument(); document->execCommand(SysAllocString(command.wc_str()), VARIANT_FALSE, VARIANT(), NULL); + document->Release(); } -IHTMLDocument2* wxWebViewIE::GetDocument() +IHTMLDocument2* wxWebViewIE::GetDocument() const { wxVariant variant = m_ie.GetProperty("Document"); IHTMLDocument2* document = (IHTMLDocument2*)variant.GetVoidPtr(); @@ -583,12 +722,12 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt) wxString url = evt[1].GetString(); wxString target = evt[3].GetString(); - wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING, - GetId(), url, target, true); + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING, + GetId(), url, target); event.SetEventObject(this); HandleWindowEvent(event); - if (event.IsVetoed()) + if (!event.IsAllowed()) { wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters(); @@ -609,8 +748,8 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt) wxString url = evt[1].GetString(); // TODO: set target parameter if possible wxString target = wxEmptyString; - wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED, - GetId(), url, target, false); + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED, + GetId(), url, target); event.SetEventObject(this); HandleWindowEvent(event); break; @@ -635,16 +774,22 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt) //As we are complete we also add to the history list, but not if the //page is not the main page, ie it is a subframe - if(m_historyEnabled && !m_historyLoadingFromList && url == GetCurrentURL()) + //We also have to check if we are loading a file:// url, if so we + //need to change the comparison as ie passes back a different style + //of url + if(m_historyEnabled && !m_historyLoadingFromList && + (url == GetCurrentURL() || + (GetCurrentURL().substr(0, 4) == "file" && + wxFileSystem::URLToFileName(GetCurrentURL()).GetFullPath() == url))) { //If we are not at the end of the list, then erase everything //between us and the end before adding the new page - if(m_historyPosition != m_historyList.size() - 1) + if(m_historyPosition != static_cast(m_historyList.size()) - 1) { m_historyList.erase(m_historyList.begin() + m_historyPosition + 1, m_historyList.end()); } - wxSharedPtr item(new wxWebHistoryItem(url, GetCurrentTitle())); + wxSharedPtr item(new wxWebViewHistoryItem(url, GetCurrentTitle())); m_historyList.push_back(item); m_historyPosition++; } @@ -652,8 +797,8 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt) m_historyLoadingFromList = false; // TODO: set target parameter if possible wxString target = wxEmptyString; - wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED, GetId(), - url, target, false); + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED, GetId(), + url, target); event.SetEventObject(this); HandleWindowEvent(event); break; @@ -666,12 +811,19 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt) case DISPID_TITLECHANGE: { + wxString title = evt[0].GetString(); + + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED, + GetId(), GetCurrentURL(), ""); + event.SetString(title); + event.SetEventObject(this); + HandleWindowEvent(event); break; } case DISPID_NAVIGATEERROR: { - wxWebNavigationError errorType = wxWEB_NAV_ERR_OTHER; + wxWebViewNavigationError errorType = wxWEB_NAV_ERR_OTHER; wxString errorCode = "?"; switch (evt[3].GetLong()) { @@ -785,44 +937,27 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt) wxString url = evt[1].GetString(); wxString target = evt[2].GetString(); - wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR, GetId(), - url, target, false); + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR, GetId(), + url, target); event.SetEventObject(this); event.SetInt(errorType); event.SetString(errorCode); HandleWindowEvent(event); break; } - - case DISPID_COMMANDSTATECHANGE: - { - long commandId = evt[0].GetLong(); - bool enable = evt[1].GetBool(); - if (commandId == CSC_NAVIGATEBACK) - { - m_canNavigateBack = enable; - } - else if (commandId == CSC_NAVIGATEFORWARD) - { - m_canNavigateForward = enable; - } - break; - } case DISPID_NEWWINDOW3: { wxString url = evt[4].GetString(); - wxWebNavigationEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW, - GetId(), url, wxEmptyString, true); + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW, + GetId(), url, wxEmptyString); event.SetEventObject(this); HandleWindowEvent(event); - //If we veto the event then we cancel the new window - if (event.IsVetoed()) - { - wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters(); - *V_BOOLREF(&nativeParams->pDispParams->rgvarg[3]) = VARIANT_TRUE; - } + //We always cancel this event otherwise an Internet Exporer window + //is opened for the url + wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters(); + *V_BOOLREF(&nativeParams->pDispParams->rgvarg[3]) = VARIANT_TRUE; break; } } @@ -830,4 +965,173 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt) evt.Skip(); } +VirtualProtocol::VirtualProtocol(wxSharedPtr handler) +{ + m_refCount = 0; + m_file = NULL; + m_handler = handler; +} + +VirtualProtocol::~VirtualProtocol() +{ +} + +ULONG VirtualProtocol::AddRef() +{ + m_refCount++; + return m_refCount; +} + +HRESULT VirtualProtocol::QueryInterface(REFIID riid, void **ppvObject) +{ + if(riid == IID_IUnknown || riid == IID_IInternetProtocolRoot || + riid == IID_IInternetProtocol) + { + *ppvObject = (IInternetProtocol*)this; + AddRef(); + return S_OK; + } + else + { + *ppvObject = NULL; + return E_POINTER; + } +} + +ULONG VirtualProtocol::Release() +{ + m_refCount--; + if (m_refCount > 0) + { + return m_refCount; + } + else + { + delete this; + return 0; + } +} + +HRESULT VirtualProtocol::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink, + IInternetBindInfo *pOIBindInfo, DWORD grfPI, + HANDLE_PTR dwReserved) +{ + wxUnusedVar(szUrl); + wxUnusedVar(pOIBindInfo); + wxUnusedVar(grfPI); + wxUnusedVar(dwReserved); + m_protocolSink = pOIProtSink; + + //We get the file itself from the protocol handler + m_file = m_handler->GetFile(szUrl); + + + if(!m_file) + return INET_E_RESOURCE_NOT_FOUND; + + //We return the stream length for current and total size as we can always + //read the whole file from the stream + wxFileOffset length = m_file->GetStream()->GetLength(); + m_protocolSink->ReportData(BSCF_FIRSTDATANOTIFICATION | + BSCF_DATAFULLYAVAILABLE | + BSCF_LASTDATANOTIFICATION, + length, length); + return S_OK; +} + +HRESULT VirtualProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead) +{ + //If the file is null we return false to indicte it is finished + if(!m_file) + return S_FALSE; + + wxStreamError err = m_file->GetStream()->Read(pv, cb).GetLastError(); + *pcbRead = m_file->GetStream()->LastRead(); + + if(err == wxSTREAM_NO_ERROR) + { + if(*pcbRead < cb) + { + wxDELETE(m_file); + m_protocolSink->ReportResult(S_OK, 0, NULL); + } + //As we are not eof there is more data + return S_OK; + } + else if(err == wxSTREAM_EOF) + { + wxDELETE(m_file); + m_protocolSink->ReportResult(S_OK, 0, NULL); + //We are eof and so finished + return S_OK; + } + else if(err == wxSTREAM_READ_ERROR) + { + wxDELETE(m_file); + return INET_E_DOWNLOAD_FAILURE; + } + else + { + //Dummy return to surpress a compiler warning + wxFAIL; + return INET_E_DOWNLOAD_FAILURE; + } +} + +HRESULT ClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid, + void ** ppvObject) +{ + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + VirtualProtocol* vp = new VirtualProtocol(m_handler); + vp->AddRef(); + HRESULT hr = vp->QueryInterface(riid, ppvObject); + vp->Release(); + return hr; + +} + +STDMETHODIMP ClassFactory::LockServer(BOOL fLock) +{ + wxUnusedVar(fLock); + return S_OK; +} + +ULONG ClassFactory::AddRef(void) +{ + m_refCount++; + return m_refCount; +} + +HRESULT ClassFactory::QueryInterface(REFIID riid, void **ppvObject) +{ + if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) + { + *ppvObject = this; + AddRef(); + return S_OK; + } + else + { + *ppvObject = NULL; + return E_POINTER; + } + +} + +ULONG ClassFactory::Release(void) +{ + m_refCount--; + if (m_refCount > 0) + { + return m_refCount; + } + else + { + delete this; + return 0; + } + +} + #endif