diff --git a/etg/_html2.py b/etg/_html2.py new file mode 100644 index 00000000..8b518fa5 --- /dev/null +++ b/etg/_html2.py @@ -0,0 +1,67 @@ +#--------------------------------------------------------------------------- +# Name: etg/_html2.py +# Author: Robin Dunn +# +# Created: 20-Nov-2012 +# Copyright: (c) 2012 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools +from etgtools import PyFunctionDef, PyCodeDef, PyPropertyDef + +PACKAGE = "wx" +MODULE = "_html2" +NAME = "_html2" # Base name of the file to generate to for this script +DOCSTRING = "" + +# The classes and/or the basename of the Doxygen XML files to be processed by +# this script. +ITEMS = [ ] + + +# The list of other ETG scripts and back-end generator modules that are +# included as part of this module. These should all be items that are put in +# the wxWidgets "webview" library in a multi-lib build. +INCLUDES = [ 'webview', + ] + + +# Separate the list into those that are generated from ETG scripts and the +# rest. These lists can be used from the build scripts to get a list of +# sources and/or additional dependencies when building this extension module. +ETGFILES = ['etg/%s.py' % NAME] + tools.getEtgFiles(INCLUDES) +DEPENDS = tools.getNonEtgFiles(INCLUDES) +OTHERDEPS = [ ] + + +#--------------------------------------------------------------------------- + +def run(): + # Parse the XML file(s) building a collection of Extractor objects + module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING) + etgtools.parseDoxyXML(module, ITEMS) + module.check4unittest = False + + #----------------------------------------------------------------- + # Tweak the parsed meta objects in the module object as needed for + # customizing the generated code and docstrings. + + module.addHeaderCode('#include ') + module.addImport('_core') + module.addPyCode('import wx', order=10) + module.addInclude(INCLUDES) + + + #----------------------------------------------------------------- + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + run() diff --git a/etg/webview.py b/etg/webview.py new file mode 100644 index 00000000..bb631cab --- /dev/null +++ b/etg/webview.py @@ -0,0 +1,124 @@ +#--------------------------------------------------------------------------- +# Name: etg/webview.py +# Author: Robin Dunn +# +# Created: 20-Nov-2012 +# Copyright: (c) 2012 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_html2" +NAME = "webview" # Base name of the file to generate to for this script +DOCSTRING = "" + +# The classes and/or the basename of the Doxygen XML files to be processed by +# this script. +ITEMS = [ 'wxWebViewHistoryItem', + 'wxWebViewHandler', + 'wxWebViewArchiveHandler', + 'wxWebViewFSHandler', + 'wxWebView', + 'wxWebViewEvent', + ] + +#--------------------------------------------------------------------------- + +def run(): + # Parse the XML file(s) building a collection of Extractor objects + module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING) + etgtools.parseDoxyXML(module, ITEMS) + + #----------------------------------------------------------------- + # Tweak the parsed meta objects in the module object as needed for + # customizing the generated code and docstrings. + + module.addHeaderCode('#include ') + + c = module.find('wxWebView') + assert isinstance(c, etgtools.ClassDef) + tools.fixWindowClass(c) + c.abstract = True + + module.addGlobalStr('wxWebViewNameStr', c) + module.addGlobalStr('wxWebViewDefaultURLStr', c) + + for m in c.find('New').all(): + m.factory = True + c.find('New.id').default = 'wxID_ANY' + c.find('New.parent').transferThis = True + + + c.find('RegisterHandler.handler').type = 'wxWebViewHandler*' + c.find('RegisterHandler.handler').transfer = True + c.find('RegisterHandler').setCppCode_sip( + "sipCpp->RegisterHandler(wxSharedPtr(handler));") + + + # Custom code to deal with the + # wxVector> return type of these two + # methods. We'll just convert them to a Python list of history items. + code = """\ + wxPyThreadBlocker blocker; + PyObject* result = PyList_New(0); + wxVector > vector = self->{method}(); + for (size_t idx=0; idx < vector.size(); idx++) {{ + PyObject* obj; + wxWebViewHistoryItem* item = new wxWebViewHistoryItem(*vector[idx].get()); + obj = wxPyConstructObject((void*)item, "wxWebViewHistoryItem", true); + PyList_Append(result, obj); + Py_DECREF(obj); + }} + return result; + """ + c.find('GetBackwardHistory').type = 'PyObject*' + c.find('GetBackwardHistory').setCppCode(code.format(method='GetBackwardHistory')) + c.find('GetForwardHistory').type = 'PyObject*' + c.find('GetForwardHistory').setCppCode(code.format(method='GetForwardHistory')) + + + # Since LoadHistoryItem expects to get an actual item in the history + # list, and since we make copies of the items in the cppCode above, then + # this won't be possible to do from the Python wrappers. However, it's + # just as easy to use LoadURL to reload a history item so it's not a + # great loss. + c.find('LoadHistoryItem').ignore() + ##c.find('LoadHistoryItem.item').type = 'wxWebViewHistoryItem*' + ##c.find('LoadHistoryItem.item').transfer = True + ##c.find('LoadHistoryItem').setCppCode_sip( + ## "sipCpp->LoadHistoryItem(wxSharedPtr(item));") + + + + + + c = module.find('wxWebViewEvent') + tools.fixEventClass(c) + + module.addPyCode("""\ + EVT_WEB_VIEW_NAVIGATING = wx.PyEventBinder( wxEVT_COMMAND_WEB_VIEW_NAVIGATING, 1 ) + EVT_WEB_VIEW_NAVIGATED = wx.PyEventBinder( wxEVT_COMMAND_WEB_VIEW_NAVIGATED, 1 ) + EVT_WEB_VIEW_LOADED = wx.PyEventBinder( wxEVT_COMMAND_WEB_VIEW_LOADED, 1 ) + EVT_WEB_VIEW_ERROR = wx.PyEventBinder( wxEVT_COMMAND_WEB_VIEW_ERROR, 1 ) + EVT_WEB_VIEW_NEWWINDOW = wx.PyEventBinder( wxEVT_COMMAND_WEB_VIEW_NEWWINDOW, 1 ) + EVT_WEB_VIEW_TITLE_CHANGED = wx.PyEventBinder( wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED, 1 ) + """) + + + + c = module.find('wxWebViewHistoryItem') + tools.addAutoProperties(c) + + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() + diff --git a/samples/html2/HTML2_WebView.py b/samples/html2/HTML2_WebView.py new file mode 100644 index 00000000..07de949c --- /dev/null +++ b/samples/html2/HTML2_WebView.py @@ -0,0 +1,161 @@ +import sys +import wx +import wx.html2 as webview + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + + self.current = "http://wxPython.org" + self.frame = self.GetTopLevelParent() + self.titleBase = self.frame.GetTitle() + + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + self.wv = webview.WebView.New(self) + self.Bind(webview.EVT_WEB_VIEW_NAVIGATING, self.OnWebViewNavigating, self.wv) + self.Bind(webview.EVT_WEB_VIEW_NAVIGATED, self.OnWebViewNavigated, self.wv) + self.Bind(webview.EVT_WEB_VIEW_LOADED, self.OnWebViewLoaded, self.wv) + self.Bind(webview.EVT_WEB_VIEW_TITLE_CHANGED, self.OnWebViewTitleChanged, self.wv) + + btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "<--", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoBack, btn) + + btn = wx.Button(self, -1, "-->", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoForward, btn) + + btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + txt = wx.StaticText(self, -1, "Location:") + btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2) + + self.location = wx.ComboBox( + self, -1, "", style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER) + self.location.AppendItems(['http://wxPython.org', + 'http://wxwidgets.org', + 'http://google.com']) + + #for url in ['http://wxPython.org', + # 'http://wxwidgets.org', + # 'http://google.com']: + # item = webview.WebViewHistoryItem(url, url) + # self.wv.LoadHistoryItem(item) + + self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location) + self.location.Bind(wx.EVT_TEXT_ENTER, self.OnLocationEnter) + btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2) + + + sizer.Add(btnSizer, 0, wx.EXPAND) + sizer.Add(self.wv, 1, wx.EXPAND) + self.SetSizer(sizer) + + self.wv.LoadURL(self.current) + + + + # WebView events + def OnWebViewNavigating(self, evt): + # this event happens prior to trying to get a resource + if evt.GetURL() == 'http://www.microsoft.com/': + if wx.MessageBox("Are you sure you want to visit Microsoft?", + style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO: + # This is how you can cancel loading a page. + evt.Veto() + + + def OnWebViewNavigated(self, evt): + self.frame.SetStatusText("Loading %s..." % evt.GetURL()) + + + def OnWebViewLoaded(self, evt): + # The full document has loaded + self.current = evt.GetURL() + self.location.SetValue(self.current) + self.frame.SetStatusText("Loaded") + + + def OnWebViewTitleChanged(self, evt): + # Set the frame's title to include the document's title + self.frame.SetTitle("%s -- %s" % (self.titleBase, evt.GetString())) + + + # Control bar events + def OnLocationSelect(self, evt): + url = self.location.GetStringSelection() + print('OnLocationSelect: %s\n' % url) + self.wv.LoadURL(url) + + def OnLocationEnter(self, evt): + url = self.location.GetValue() + self.location.Append(url) + self.wv.LoadURL(url) + + + def OnOpenButton(self, event): + dlg = wx.TextEntryDialog(self, "Open Location", + "Enter a full URL or local path", + self.current, wx.OK|wx.CANCEL) + dlg.CentreOnParent() + + if dlg.ShowModal() == wx.ID_OK: + self.current = dlg.GetValue() + self.wv.LoadURL(self.current) + + dlg.Destroy() + + def OnPrevPageButton(self, event): + for i in self.wv.GetBackwardHistory(): + print i.Url, i.Title + self.wv.GoBack() + + def OnNextPageButton(self, event): + for i in self.wv.GetForwardHistory(): + print i.URL, i.Title + self.wv.GoForward() + + def OnCheckCanGoBack(self, event): + event.Enable(self.wv.CanGoBack()) + + def OnCheckCanGoForward(self, event): + event.Enable(self.wv.CanGoForward()) + + def OnStopButton(self, evt): + self.wv.Stop() + + def OnRefreshPageButton(self, evt): + self.wv.Reload() + + +#---------------------------------------------------------------------- + + +def main(): + app = wx.App() + frm = wx.Frame(None, title="html2.WebView sample", size=(700,500)) + frm.CreateStatusBar() + pnl = TestPanel(frm) + frm.Show() + app.MainLoop() + + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index 06d27ee5..be26bdb9 100644 --- a/setup.py +++ b/setup.py @@ -229,6 +229,22 @@ extensions.append(ext) cfg.CLEANUP.append(opj(cfg.PKGDIR, 'glcanvas.py')) +etg = loadETG('etg/_html2.py') +tgDepends = etg.DEPENDS + etg.OTHERDEPS +ext = Extension('_html2', getEtgSipCppFiles(etg), + depends = getEtgSipHeaders(etg), + include_dirs = cfg.includes, + define_macros = cfg.defines, + library_dirs = cfg.libdirs, + libraries = cfg.libs + cfg.makeLibName('webview', True), + extra_compile_args = cfg.cflags, + extra_link_args = cfg.lflags, + ) +extensions.append(ext) +cfg.CLEANUP.append(opj(cfg.PKGDIR, 'html2.py')) + + + #---------------------------------------------------------------------- if __name__ == '__main__': diff --git a/unittests/test_pi_import.py b/unittests/test_pi_import.py index 7912d8dd..e8f2997c 100644 --- a/unittests/test_pi_import.py +++ b/unittests/test_pi_import.py @@ -43,6 +43,9 @@ class PIImportTest(unittest.TestCase): def test_html_pi(self): self.runPI('html.pi') + def test_html2_pi(self): + self.runPI('html2.pi') + def test_dataview_pi(self): self.runPI('dataview.pi') diff --git a/unittests/test_webview.py b/unittests/test_webview.py new file mode 100644 index 00000000..de8cdb42 --- /dev/null +++ b/unittests/test_webview.py @@ -0,0 +1,78 @@ +import imp_unittest, unittest +import wtc +import wx +import wx.html2 as webview + +#--------------------------------------------------------------------------- + +class webview_Tests(wtc.WidgetTestCase): + + def test_webview1(self): + wv = webview.WebView.New() + wv.Create(self.frame) + + def test_webview2(self): + wv = webview.WebView.New(self.frame) + + def test_webview3(self): + wv = webview.WebView.New(self.frame) + self.frame.SendSizeEvent() + wv.LoadURL('file://' + __file__) + while wv.IsBusy(): + self.myYield() + h = wv.GetBackwardHistory() + self.assertTrue(isinstance(h, list)) + if len(h): + self.assertTrue(isinstance(h[0], webview.WebViewHistoryItem)) + + + def test_webview5(self): + webview.WEB_VIEW_ZOOM_TINY + webview.WEB_VIEW_ZOOM_SMALL + webview.WEB_VIEW_ZOOM_MEDIUM + webview.WEB_VIEW_ZOOM_LARGE + webview.WEB_VIEW_ZOOM_LARGEST + webview.WEB_VIEW_ZOOM_TYPE_LAYOUT + webview.WEB_VIEW_ZOOM_TYPE_TEXT + webview.WEB_NAV_ERR_CONNECTION + webview.WEB_NAV_ERR_CERTIFICATE + webview.WEB_NAV_ERR_AUTH + webview.WEB_NAV_ERR_SECURITY + webview.WEB_NAV_ERR_NOT_FOUND + webview.WEB_NAV_ERR_REQUEST + webview.WEB_NAV_ERR_USER_CANCELLED + webview.WEB_NAV_ERR_OTHER + webview.WEB_VIEW_RELOAD_DEFAULT + webview.WEB_VIEW_RELOAD_NO_CACHE + webview.WEB_VIEW_FIND_WRAP + webview.WEB_VIEW_FIND_ENTIRE_WORD + webview.WEB_VIEW_FIND_MATCH_CASE + webview.WEB_VIEW_FIND_HIGHLIGHT_RESULT + webview.WEB_VIEW_FIND_BACKWARDS + webview.WEB_VIEW_FIND_DEFAULT + webview.WEB_VIEW_BACKEND_DEFAULT + webview.WEB_VIEW_BACKEND_WEBKIT + webview.WEB_VIEW_BACKEND_IE + + + def test_webview6(self): + webview.wxEVT_COMMAND_WEB_VIEW_NAVIGATING + webview.wxEVT_COMMAND_WEB_VIEW_NAVIGATED + webview.wxEVT_COMMAND_WEB_VIEW_LOADED + webview.wxEVT_COMMAND_WEB_VIEW_ERROR + webview.wxEVT_COMMAND_WEB_VIEW_NEWWINDOW + webview.wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED + + webview.EVT_WEB_VIEW_NAVIGATING + webview.EVT_WEB_VIEW_NAVIGATED + webview.EVT_WEB_VIEW_LOADED + webview.EVT_WEB_VIEW_ERROR + webview.EVT_WEB_VIEW_NEWWINDOW + webview.EVT_WEB_VIEW_TITLE_CHANGED + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + unittest.main() diff --git a/wscript b/wscript index c8cb9257..39acd96e 100644 --- a/wscript +++ b/wscript @@ -90,6 +90,8 @@ def configure(conf): _copyEnvGroup(conf.env, '_WX', '_WXGL') conf.env.LIB_WXGL += cfg.makeLibName('gl') + _copyEnvGroup(conf.env, '_WX', '_WXWEBVIEW') + conf.env.LIB_WXWEBVIEW += cfg.makeLibName('webview') @@ -142,6 +144,10 @@ def configure(conf): args='--cxxflags --libs gl,core,net', uselib_store='WXGL', mandatory=True) + conf.check_cfg(path=conf.options.wx_config, package='', + args='--cxxflags --libs webview,core,net', + uselib_store='WXWEBVIEW', mandatory=True) + # NOTE: This assumes that if the platform is not win32 (from # the test above) and not darwin then we must be using the @@ -314,6 +320,16 @@ def build(bld): makeExtCopyRule(bld, '_glcanvas') + etg = loadETG('etg/_html2.py') + adv = bld( + features = 'c cxx cxxshlib pyext', + target = makeTargetName(bld, '_html2'), + source = getEtgSipCppFiles(etg) + rc, + uselib = 'WXWEBVIEW WXPY', + ) + makeExtCopyRule(bld, '_html2') + + #----------------------------------------------------------------------------- # helpers