From 4d5faa286827ab96f0a64cf348d97e95af9b999e Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 30 Nov 2012 22:32:53 +0000 Subject: [PATCH] Add _xml and _xrc modules with some unit tests git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@73080 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- TODO.txt | 2 - docs/MigrationGuide.txt | 13 +++ docs/sphinx/_templates/main.html | 6 ++ etg/_xml.py | 99 +++++++++++++++++++ etg/_xrc.py | 160 +++++++++++++++++++++++++++++++ setup.py | 31 ++++++ unittests/test_pi_import.py | 12 ++- unittests/test_xml.py | 43 +++++++++ unittests/test_xrc.py | 60 ++++++++++++ unittests/xrctest.xrc | 66 +++++++++++++ wscript | 69 +++++++++---- 11 files changed, 536 insertions(+), 25 deletions(-) create mode 100644 etg/_xml.py create mode 100644 etg/_xrc.py create mode 100644 unittests/test_xml.py create mode 100644 unittests/test_xrc.py create mode 100644 unittests/xrctest.xrc diff --git a/TODO.txt b/TODO.txt index 3cee5bd4..e7db0cf7 100644 --- a/TODO.txt +++ b/TODO.txt @@ -139,8 +139,6 @@ other dev stuff * Add _propdlg module - * Add _xrc module (containg xrc and xml classes) - * Add _richtext module * Add _aui module ?? (or go with only agw aui) diff --git a/docs/MigrationGuide.txt b/docs/MigrationGuide.txt index 8cf2e436..c61b9d8a 100644 --- a/docs/MigrationGuide.txt +++ b/docs/MigrationGuide.txt @@ -383,6 +383,19 @@ with a wx.ComboPopup in a has-a relationship rather than an is-a relationship. See samples/combo/combo1.py for an example. + +XRC +------- + +The "LoadOnFoo" methods of the XmlResource class were renamed overloads of +the coresponding "LoadFoo" methods. Since we no longer need to rename +overloaded methods the "LoadOn" version has been removed and you should just +use the "LoadFoo" version instead. These methods are used to load some XRC +content onto an existing window, such as a Frame, instead of creating a new +Frame for the content. + + + .. toctree:: :maxdepth: 2 :hidden: diff --git a/docs/sphinx/_templates/main.html b/docs/sphinx/_templates/main.html index 93cdd7d9..76581117 100644 --- a/docs/sphinx/_templates/main.html +++ b/docs/sphinx/_templates/main.html @@ -79,6 +79,12 @@ + + + + diff --git a/etg/_xml.py b/etg/_xml.py new file mode 100644 index 00000000..72095808 --- /dev/null +++ b/etg/_xml.py @@ -0,0 +1,99 @@ +#--------------------------------------------------------------------------- +# Name: etg/_xml.py +# Author: Robin Dunn +# +# Created: 28-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 = "_xml" +NAME = "_xml" # 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 = [ 'wxXmlNode', + 'wxXmlAttribute', + 'wxXmlDocument', + ] + + +# 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 "xml" library in a multi-lib build. +INCLUDES = [ ] + + +# 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) + + + #----------------------------------------------------------------- + + + module.addPyCode("""\ + XmlProperty = wx.deprecated(XmlAttribute, 'Use XmlProperty instead.') + """) + + c = module.find('wxXmlNode') + assert isinstance(c, etgtools.ClassDef) + + c.find('wxXmlNode.parent').transferThis = True + + c.find('AddAttribute.attr').transfer = True + c.find('AddChild.child').transfer = True + c.find('InsertChild.child').transfer = True + c.find('InsertChildAfter.child').transfer = True + c.find('RemoveChild.child').transferBack = True + + # we like the other overload better + c.find('GetAttribute').findOverload('value').ignore() + + c.find('SetAttributes').ignore() + c.find('SetChildren').ignore() + + + + c = module.find('wxXmlDocument') + c.find('GetEncoding').ignore() + c.find('SetEncoding').ignore() + + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + run() diff --git a/etg/_xrc.py b/etg/_xrc.py new file mode 100644 index 00000000..f35c0a41 --- /dev/null +++ b/etg/_xrc.py @@ -0,0 +1,160 @@ +#--------------------------------------------------------------------------- +# Name: etg/_xrc.py +# Author: Robin Dunn +# +# Created: 28-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 = "_xrc" +NAME = "_xrc" # 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 = [ 'wxXmlResource', + 'wxXmlResourceHandler', + ] + + +# 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 "xrc" library in a multi-lib build. +INCLUDES = [ ] + + +# 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.addImport('_xml') + module.addPyCode('import wx', order=10) + module.addInclude(INCLUDES) + + module.addInitializerCode("""\ + wxXmlInitResourceModule(); + """) + + module.addHeaderCode('#include ') + module.addHeaderCode('#include ') + module.addHeaderCode('#include "wxpybuffer.h"') + + #----------------------------------------------------------------- + + + c = module.find('wxXmlResource') + assert isinstance(c, etgtools.ClassDef) + c.addPrivateCopyCtor() + + # Add a bit of code to the ctors to call InitAllHandlers(), for + # compatibility with Classic + for ctor in c.find('wxXmlResource').all(): + template = """\ + Py_BEGIN_ALLOW_THREADS + sipCpp = new sipwxXmlResource({args}); + sipCpp->InitAllHandlers(); + Py_END_ALLOW_THREADS + """ + if 'filemask' in ctor.argsString: + args = '*filemask,flags,*domain' + else: + args = 'flags,*domain' + ctor.setCppCode_sip(template.format(args=args)) + + + c.addPublic() + c.addCppMethod('bool', 'LoadFromString', '(wxPyBuffer* data)', + doc="Load the resource from a string or other data buffer compatible object.", + #protection='public', + body="""\ + static int s_memFileIdx = 0; + + // Check for memory FS. If not present, load the handler: + wxMemoryFSHandler::AddFile(wxT("XRC_resource/dummy_file"), + wxT("dummy data")); + wxFileSystem fsys; + wxFSFile *f = fsys.OpenFile(wxT("memory:XRC_resource/dummy_file")); + wxMemoryFSHandler::RemoveFile(wxT("XRC_resource/dummy_file")); + if (f) + delete f; + else + wxFileSystem::AddHandler(new wxMemoryFSHandler); + + // Now put the resource data into the memory FS + wxString filename(wxT("XRC_resource/data_string_")); + filename << s_memFileIdx; + s_memFileIdx += 1; + wxMemoryFSHandler::AddFile(filename, data->m_ptr, data->m_len); + + // Load the "file" into the resource object + bool retval = self->Load(wxT("memory:") + filename ); + return retval; + """) + + c.find('AddHandler.handler').transfer = True + c.find('InsertHandler').transfer = True + c.find('Set.res').transfer = True + c.find('Set').transferBack = True + + + module.addPyFunction('EmptyXmlResource', '(flags=XRC_USE_LOCALE, domain="")', + deprecated="Use XmlResource instead", + doc='A compatibility wrapper for the XmlResource(flags, domain) constructor', + body='return XmlResource(flags, domain)') + + module.addPyFunction('XRCID', '(str_id, value_if_not_found=wx.ID_NONE)', + doc='Returns a numeric ID that is equivalent to the string ID used in an XML resource.', + body='return XmlResource.GetXRCID(str_id, value_if_not_found)') + + module.addPyFunction('XRCCTRL', '(window, str_id, *ignoreargs)', + doc='Returns the child window associated with the string ID in an XML resource.', + body='return window.FindWindowById(XRCID(str_id))') + + + + module.addItem(etgtools.WigCode("""\ + class wxXmlSubclassFactory + { + public: + wxXmlSubclassFactory(); + virtual ~wxXmlSubclassFactory(); + virtual wxObject *Create(const wxString& className) = 0; + };""")) + + + + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + run() diff --git a/setup.py b/setup.py index be26bdb9..af1064c7 100644 --- a/setup.py +++ b/setup.py @@ -244,6 +244,37 @@ extensions.append(ext) cfg.CLEANUP.append(opj(cfg.PKGDIR, 'html2.py')) +etg = loadETG('etg/_xml.py') +tgDepends = etg.DEPENDS + etg.OTHERDEPS +ext = Extension('_xml', getEtgSipCppFiles(etg), + depends = getEtgSipHeaders(etg), + include_dirs = cfg.includes, + define_macros = cfg.defines, + library_dirs = cfg.libdirs, + libraries = cfg.libs + cfg.makeLibName('xml', True), + extra_compile_args = cfg.cflags, + extra_link_args = cfg.lflags, + ) +extensions.append(ext) +cfg.CLEANUP.append(opj(cfg.PKGDIR, 'xml.py')) + + +etg = loadETG('etg/_xrc.py') +tgDepends = etg.DEPENDS + etg.OTHERDEPS +ext = Extension('_xrc', getEtgSipCppFiles(etg), + depends = getEtgSipHeaders(etg), + include_dirs = cfg.includes, + define_macros = cfg.defines, + library_dirs = cfg.libdirs, + libraries = cfg.libs + cfg.makeLibName('xml', True) + cfg.makeLibName('xrc', True), + extra_compile_args = cfg.cflags, + extra_link_args = cfg.lflags, + ) +extensions.append(ext) +cfg.CLEANUP.append(opj(cfg.PKGDIR, 'xrc.py')) + + + #---------------------------------------------------------------------- diff --git a/unittests/test_pi_import.py b/unittests/test_pi_import.py index e8f2997c..46c42a0e 100644 --- a/unittests/test_pi_import.py +++ b/unittests/test_pi_import.py @@ -34,8 +34,8 @@ class PIImportTest(unittest.TestCase): def test_core_pi(self): self.runPI('core.pi') - #def test_adv_pi(self): - # self.runPI('adv.pi') + def test_adv_pi(self): + self.runPI('adv.pi') def test_stc_pi(self): self.runPI('stc.pi') @@ -48,6 +48,14 @@ class PIImportTest(unittest.TestCase): def test_dataview_pi(self): self.runPI('dataview.pi') + + def test_xml_pi(self): + self.runPI('xml.pi') + + def test_xrc_pi(self): + self.runPI('xrc.pi') + + #--------------------------------------------------------------------------- diff --git a/unittests/test_xml.py b/unittests/test_xml.py new file mode 100644 index 00000000..79163156 --- /dev/null +++ b/unittests/test_xml.py @@ -0,0 +1,43 @@ +import imp_unittest, unittest +import wtc +import wx +import wx.xml as xml + +#--------------------------------------------------------------------------- + +class xml_Tests(wtc.WidgetTestCase): + + def test_xml1(self): + doc = xml.XmlDocument() + node = xml.XmlNode(xml.XML_DOCUMENT_NODE, 'document') + doc.SetDocumentNode(node) + root = xml.XmlNode(xml.XML_ELEMENT_NODE, 'root') + node.AddChild(root) + root.AddAttribute('name1', 'value1') + root.AddAttribute(xml.XmlAttribute('name2', 'value2')) + + + def test_xml2(self): + xml.XML_ELEMENT_NODE + xml.XML_ATTRIBUTE_NODE + xml.XML_TEXT_NODE + xml.XML_CDATA_SECTION_NODE + xml.XML_ENTITY_REF_NODE + xml.XML_ENTITY_NODE + xml.XML_PI_NODE + xml.XML_COMMENT_NODE + xml.XML_DOCUMENT_NODE + xml.XML_DOCUMENT_TYPE_NODE + xml.XML_DOCUMENT_FRAG_NODE + xml.XML_NOTATION_NODE + xml.XML_HTML_DOCUMENT_NODE + + xml.XML_NO_INDENTATION + xml.XMLDOC_NONE + xml.XMLDOC_KEEP_WHITESPACE_NODES + +#--------------------------------------------------------------------------- + + +if __name__ == '__main__': + unittest.main() diff --git a/unittests/test_xrc.py b/unittests/test_xrc.py new file mode 100644 index 00000000..d1a6e1bd --- /dev/null +++ b/unittests/test_xrc.py @@ -0,0 +1,60 @@ +import imp_unittest, unittest +import wtc +import wx +import wx.xrc as xrc +import os + +xrcFile = os.path.join(os.path.dirname(__file__), 'xrctest.xrc') + +#--------------------------------------------------------------------------- + +class xrc_Tests(wtc.WidgetTestCase): + + def checkXmlRes(self, xmlres): + assert isinstance(xmlres, xrc.XmlResource) + #xmlres.InitAllHandlers() + f = xmlres.LoadFrame(self.frame, 'MainFrame') + self.assertNotEqual(f, None) + f.Show() + + self.myYield() + + id = xrc.XRCID('MainPanel') + self.assertTrue(id != -1) + self.assertTrue(isinstance(id, int)) + + ctrl = xrc.XRCCTRL(f, 'TitleText') + self.assertTrue(ctrl != None) + self.assertTrue(isinstance(ctrl, wx.StaticText)) + + + + + def test_xrc1(self): + xmlres = xrc.XmlResource(xrcFile) + self.checkXmlRes(xmlres) + + def test_xrc2(self): + xmlres = xrc.XmlResource() + xmlres.LoadFile(xrcFile) + self.checkXmlRes(xmlres) + + def test_xrc3(self): + xmlres = xrc.XmlResource() + text = open(xrcFile).read() + xmlres.LoadFromString(text) + self.checkXmlRes(xmlres) + + def test_xrc4(self): + xmlres = xrc.XmlResource(xrcFile) + p = xmlres.LoadObjectRecursively(self.frame, 'MainPanel', 'wxPanel') + self.assertNotEqual(p, None) + self.frame.SendSizeEvent() + self.myYield() + + +#--------------------------------------------------------------------------- + + +if __name__ == '__main__': + unittest.main() diff --git a/unittests/xrctest.xrc b/unittests/xrctest.xrc new file mode 100644 index 00000000..88612b08 --- /dev/null +++ b/unittests/xrctest.xrc @@ -0,0 +1,66 @@ + + + + + wxVERTICAL + + + + wxVERTICAL + + + + #3056D3 + + 24 + + bold + 0 + swiss + + + wxALL|wxEXPAND|wxALIGN_CENTRE + 10 + + + + wxEXPAND + + + + + + + + wxALIGN_CENTRE_VERTICAL + + + + wxEXPAND + + + 5,5 + + + + + 2 + 0 + 5 + 5 + 1 + + + wxALL|wxEXPAND + 10 + + + + + wxEXPAND + + + 400,250 + This is a test + + \ No newline at end of file diff --git a/wscript b/wscript index 39acd96e..47fe6fb8 100644 --- a/wscript +++ b/wscript @@ -93,6 +93,13 @@ def configure(conf): _copyEnvGroup(conf.env, '_WX', '_WXWEBVIEW') conf.env.LIB_WXWEBVIEW += cfg.makeLibName('webview') + _copyEnvGroup(conf.env, '_WX', '_WXXML') + conf.env.LIB_WXWEBVIEW += cfg.makeLibName('xml') + + _copyEnvGroup(conf.env, '_WX', '_WXXRC') + conf.env.LIB_WXWEBVIEW += cfg.makeLibName('xrc') + + # tweak the PYEXT compile and link flags if making a --debug build @@ -148,6 +155,15 @@ def configure(conf): args='--cxxflags --libs webview,core,net', uselib_store='WXWEBVIEW', mandatory=True) + conf.check_cfg(path=conf.options.wx_config, package='', + args='--cxxflags --libs xml,core,net', + uselib_store='WXXML', mandatory=True) + + conf.check_cfg(path=conf.options.wx_config, package='', + args='--cxxflags --libs xrc,xml,core,net', + uselib_store='WXXRC', 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 @@ -261,75 +277,86 @@ def build(bld): etg = loadETG('etg/_core.py') rc = ['src/wxc.rc'] if isWindows else [] - core = bld( - features = 'c cxx cxxshlib pyext', + bld(features = 'c cxx cxxshlib pyext', target = makeTargetName(bld, '_core'), source = getEtgSipCppFiles(etg) + rc, uselib = 'WX WXPY', - ) + ) makeExtCopyRule(bld, '_core') etg = loadETG('etg/_adv.py') - adv = bld( - features = 'c cxx cxxshlib pyext', + bld(features = 'c cxx cxxshlib pyext', target = makeTargetName(bld, '_adv'), source = getEtgSipCppFiles(etg) + rc, uselib = 'WXADV WXPY', - ) + ) makeExtCopyRule(bld, '_adv') etg = loadETG('etg/_dataview.py') - dataview = bld( - features = 'c cxx cxxshlib pyext', + bld(features = 'c cxx cxxshlib pyext', target = makeTargetName(bld, '_dataview'), source = getEtgSipCppFiles(etg) + rc, uselib = 'WXADV WXPY', # dataview classes are also in the adv library - ) + ) makeExtCopyRule(bld, '_dataview') etg = loadETG('etg/_stc.py') - stc = bld( - features = 'c cxx cxxshlib pyext', + bld(features = 'c cxx cxxshlib pyext', target = makeTargetName(bld, '_stc'), source = getEtgSipCppFiles(etg) + rc, uselib = 'WXSTC WXPY', - ) + ) makeExtCopyRule(bld, '_stc') etg = loadETG('etg/_html.py') - adv = bld( - features = 'c cxx cxxshlib pyext', + bld(features = 'c cxx cxxshlib pyext', target = makeTargetName(bld, '_html'), source = getEtgSipCppFiles(etg) + rc, uselib = 'WXHTML WXPY', - ) + ) makeExtCopyRule(bld, '_html') etg = loadETG('etg/_glcanvas.py') - adv = bld( - features = 'c cxx cxxshlib pyext', + bld(features = 'c cxx cxxshlib pyext', target = makeTargetName(bld, '_glcanvas'), source = getEtgSipCppFiles(etg) + rc, uselib = 'WXGL WXPY', - ) + ) makeExtCopyRule(bld, '_glcanvas') etg = loadETG('etg/_html2.py') - adv = bld( - features = 'c cxx cxxshlib pyext', + bld(features = 'c cxx cxxshlib pyext', target = makeTargetName(bld, '_html2'), source = getEtgSipCppFiles(etg) + rc, uselib = 'WXWEBVIEW WXPY', - ) + ) makeExtCopyRule(bld, '_html2') + etg = loadETG('etg/_xml.py') + bld(features = 'c cxx cxxshlib pyext', + target = makeTargetName(bld, '_xml'), + source = getEtgSipCppFiles(etg) + rc, + uselib = 'WXXML WXPY', + ) + makeExtCopyRule(bld, '_xml') + + + etg = loadETG('etg/_xrc.py') + bld(features = 'c cxx cxxshlib pyext', + target = makeTargetName(bld, '_xrc'), + source = getEtgSipCppFiles(etg) + rc, + uselib = 'WXXRC WXPY', + ) + makeExtCopyRule(bld, '_xrc') + + #----------------------------------------------------------------------------- # helpers