From af0ac990fc6a8fabdb1255152dc027a91972d8a3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 14 Sep 2009 23:22:00 +0000 Subject: [PATCH] Add wxXmlResource::LoadObjectRecursively(). These methods can be used to load objects from anywhere in the XRC resource tree and not just from the top level. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61934 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/xrc/xmlres.h | 57 +++++++++++++++++++++++++++++++--- interface/wx/xrc/xmlres.h | 25 +++++++++++++++ samples/xrc/myframe.cpp | 42 +++++++++++++++++++++++++ samples/xrc/myframe.h | 1 + samples/xrc/rc/menu.xrc | 4 +++ src/xrc/xmlres.cpp | 65 +++++++++++++++++++++++---------------- 7 files changed, 165 insertions(+), 30 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 24e241ff9d..9862a02889 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -413,6 +413,7 @@ All (GUI): - wxPropertyGrid: added wxPG_NO_INTERNAL_BORDER, wxPG_EX_NO_TOOLBAR_DIVIDER and wxPG_EX_TOOLBAR_SEPARATOR styles for finer control over borders. Borders around property grid are now native for consistency. +- Added wxXmlResource::LoadObjectRecursively(). GTK: diff --git a/include/wx/xrc/xmlres.h b/include/wx/xrc/xmlres.h index 97c1732d89..bee65df5a4 100644 --- a/include/wx/xrc/xmlres.h +++ b/include/wx/xrc/xmlres.h @@ -188,13 +188,40 @@ public: // Load an object from the resource specifying both the resource name and // the classname. This lets you load nonstandard container windows. wxObject *LoadObject(wxWindow *parent, const wxString& name, - const wxString& classname); + const wxString& classname) + { + return DoLoadObject(parent, name, classname, false /* !recursive */); + } // Load an object from the resource specifying both the resource name and // the classname. This form lets you finish the creation of an existing // instance. - bool LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, - const wxString& classname); + bool LoadObject(wxObject *instance, + wxWindow *parent, + const wxString& name, + const wxString& classname) + { + return DoLoadObject(instance, parent, name, classname, false); + } + + // These versions of LoadObject() look for the object with the given name + // recursively (breadth first) and can be used to instantiate an individual + // control defined anywhere in an XRC file. No check is done that the name + // is unique, it's up to the caller to ensure this. + wxObject *LoadObjectRecursively(wxWindow *parent, + const wxString& name, + const wxString& classname) + { + return DoLoadObject(parent, name, classname, true /* recursive */); + } + + bool LoadObjectRecursively(wxObject *instance, + wxWindow *parent, + const wxString& name, + const wxString& classname) + { + return DoLoadObject(instance, parent, name, classname, true); + } // Loads a bitmap resource from a file. wxBitmap LoadBitmap(const wxString& name); @@ -309,7 +336,11 @@ protected: // (Uses only 'handlerToUse' if != NULL) wxObject *CreateResFromNode(wxXmlNode *node, wxObject *parent, wxObject *instance = NULL, - wxXmlResourceHandler *handlerToUse = NULL); + wxXmlResourceHandler *handlerToUse = NULL) + { + return node ? DoCreateResFromNode(*node, parent, instance, handlerToUse) + : NULL; + } // Helper of Load() and Unload(): returns the URL corresponding to the // given file if it's indeed a file, otherwise returns the original string @@ -326,6 +357,24 @@ private: wxXmlResourceDataRecords& Data() { return *m_data; } const wxXmlResourceDataRecords& Data() const { return *m_data; } + // the real implementation of CreateResFromNode(): this should be only + // called if node is non-NULL + wxObject *DoCreateResFromNode(wxXmlNode& node, + wxObject *parent, + wxObject *instance, + wxXmlResourceHandler *handlerToUse = NULL); + + // common part of LoadObject() and LoadObjectRecursively() + wxObject *DoLoadObject(wxWindow *parent, + const wxString& name, + const wxString& classname, + bool recursive); + bool DoLoadObject(wxObject *instance, + wxWindow *parent, + const wxString& name, + const wxString& classname, + bool recursive); + private: long m_version; diff --git a/interface/wx/xrc/xmlres.h b/interface/wx/xrc/xmlres.h index eba741549b..a906d188c6 100644 --- a/interface/wx/xrc/xmlres.h +++ b/interface/wx/xrc/xmlres.h @@ -286,6 +286,10 @@ public: The first overload lets you load nonstandard container windows and returns @NULL on failure. The second one lets you finish the creation of an existing instance and returns @false on failure. + + In either case, only the resources defined at the top level of XRC + files can be loaded by this function, use LoadObjectRecursively() if + you need to load an object defined deeper in the hierarchy. */ wxObject* LoadObject(wxWindow* parent, const wxString& name, const wxString& classname); @@ -294,6 +298,27 @@ public: const wxString& classname); //@} + //@{ + /** + Load an object from anywhere in the resource tree. + + These methods are similar to LoadObject() but may be used to load an + object from anywhere in the resource tree and not only the top level. + Note that you will very rarely need to do this as in normal use the + entire container window (defined at the top level) is loaded and not + its individual children but this method can be useful in some + particular situations. + + @since 2.9.1 + */ + wxObject* LoadObjectRecursively(wxWindow* parent, + const wxString& name, + const wxString& classname); + bool LoadObjectRecursively(wxObject* instance, wxWindow* parent, + const wxString& name, + const wxString& classname); + //@} + /** Loads a panel. @a parent points to the parent window. */ diff --git a/samples/xrc/myframe.cpp b/samples/xrc/myframe.cpp index 50797d3a91..0e8e1f6049 100644 --- a/samples/xrc/myframe.cpp +++ b/samples/xrc/myframe.cpp @@ -87,6 +87,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(XRCID("platform_property_tool_or_menuitem"), MyFrame::OnPlatformPropertyToolOrMenuCommand) EVT_MENU(XRCID("art_provider_tool_or_menuitem"), MyFrame::OnArtProviderToolOrMenuCommand) EVT_MENU(XRCID("variable_expansion_tool_or_menuitem"), MyFrame::OnVariableExpansionToolOrMenuCommand) + EVT_MENU(XRCID("recursive_load"), MyFrame::OnRecursiveLoad) EVT_MENU(wxID_ABOUT, MyFrame::OnAboutToolOrMenuCommand) END_EVENT_TABLE() @@ -311,6 +312,47 @@ void MyFrame::OnVariableExpansionToolOrMenuCommand(wxCommandEvent& WXUNUSED(even dlg.ShowModal(); } +void MyFrame::OnRecursiveLoad(wxCommandEvent& WXUNUSED(event)) +{ + // this dialog is created manually to show how you can inject a single + // control from XRC into an existing dialog + // + // this is a slightly contrived example, please keep in mind that it's done + // only to demonstrate LoadObjectRecursively() in action and is not the + // recommended to do this + wxDialog dlg(NULL, wxID_ANY, "Recursive Load Example", + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + wxSizer * const sizer = new wxBoxSizer(wxVERTICAL); + sizer->Add + ( + new wxStaticText + ( + &dlg, + wxID_ANY, + "The entire tree book control below is loaded from XRC" + ), + wxSizerFlags().Expand().Border() + ); + + sizer->Add + ( + static_cast + ( + // notice that controls_treebook is defined inside a notebook page + // inside a dialog defined in controls.xrc and so LoadObject() + // wouldn't find it -- but LoadObjectRecursively() does + wxXmlResource::Get()-> + LoadObjectRecursively(&dlg, "controls_treebook", "wxTreebook") + ), + wxSizerFlags(1).Expand().Border() + ); + + dlg.SetSizer(sizer); + dlg.SetClientSize(400, 200); + + dlg.ShowModal(); +} void MyFrame::OnAboutToolOrMenuCommand(wxCommandEvent& WXUNUSED(event)) { diff --git a/samples/xrc/myframe.h b/samples/xrc/myframe.h index c9f4ac9761..9701213ac8 100644 --- a/samples/xrc/myframe.h +++ b/samples/xrc/myframe.h @@ -48,6 +48,7 @@ private: void OnPlatformPropertyToolOrMenuCommand(wxCommandEvent& event); void OnArtProviderToolOrMenuCommand(wxCommandEvent& event); void OnVariableExpansionToolOrMenuCommand(wxCommandEvent& event); + void OnRecursiveLoad(wxCommandEvent& event); void OnAnimationCtrlPlay(wxCommandEvent& event); // Any class wishing to process wxWidgets events must use this macro diff --git a/samples/xrc/rc/menu.xrc b/samples/xrc/rc/menu.xrc index 91409e5c21..d60980dcf5 100644 --- a/samples/xrc/rc/menu.xrc +++ b/samples/xrc/rc/menu.xrc @@ -69,6 +69,10 @@ variable.xpm Replace variables in the XRC file at runtime + + + Show how an individual control can be loaded + diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp index 94064a2cfc..dac420862e 100644 --- a/src/xrc/xmlres.cpp +++ b/src/xrc/xmlres.cpp @@ -431,14 +431,27 @@ wxIcon wxXmlResource::LoadIcon(const wxString& name) } -wxObject *wxXmlResource::LoadObject(wxWindow *parent, const wxString& name, const wxString& classname) +wxObject * +wxXmlResource::DoLoadObject(wxWindow *parent, + const wxString& name, + const wxString& classname, + bool recursive) { - return CreateResFromNode(FindResource(name, classname), parent, NULL); + wxXmlNode * const node = FindResource(name, classname, recursive); + + return node ? DoCreateResFromNode(*node, parent, NULL) : NULL; } -bool wxXmlResource::LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, const wxString& classname) +bool +wxXmlResource::DoLoadObject(wxObject *instance, + wxWindow *parent, + const wxString& name, + const wxString& classname, + bool recursive) { - return CreateResFromNode(FindResource(name, classname), parent, instance) != NULL; + wxXmlNode * const node = FindResource(name, classname, recursive); + + return node && DoCreateResFromNode(*node, parent, instance) != NULL; } @@ -819,23 +832,23 @@ static void MergeNodesOver(wxXmlNode& dest, wxXmlNode& overwriteWith, dest.SetContent(overwriteWith.GetContent()); } -wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, - wxObject *instance, - wxXmlResourceHandler *handlerToUse) +wxObject * +wxXmlResource::DoCreateResFromNode(wxXmlNode& node, + wxObject *parent, + wxObject *instance, + wxXmlResourceHandler *handlerToUse) { - if (node == NULL) return NULL; - // handling of referenced resource - if ( node->GetName() == wxT("object_ref") ) + if ( node.GetName() == wxT("object_ref") ) { - wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString); + wxString refName = node.GetAttribute(wxT("ref"), wxEmptyString); wxXmlNode* refNode = FindResource(refName, wxEmptyString, true); if ( !refNode ) { ReportError ( - node, + &node, wxString::Format ( "referenced object node with ref=\"%s\" not found", @@ -845,14 +858,14 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, return NULL; } - if ( !node->GetChildren() ) + if ( !node.GetChildren() ) { // In the typical, simple case, is used to link // to another node and doesn't have any content of its own that // would overwrite linked object's properties. In this case, // we can simply create the resource from linked node. - return CreateResFromNode(refNode, parent, instance); + return DoCreateResFromNode(*refNode, parent, instance); } else { @@ -862,42 +875,42 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, // load the resource from result of the merge. wxXmlNode copy(*refNode); - MergeNodesOver(copy, *node, GetFileNameFromNode(node, Data())); + MergeNodesOver(copy, node, GetFileNameFromNode(&node, Data())); // remember referenced object's file, see GetFileNameFromNode() copy.AddAttribute(ATTR_INPUT_FILENAME, GetFileNameFromNode(refNode, Data())); - return CreateResFromNode(©, parent, instance); + return DoCreateResFromNode(copy, parent, instance); } } if (handlerToUse) { - if (handlerToUse->CanHandle(node)) + if (handlerToUse->CanHandle(&node)) { - return handlerToUse->CreateResource(node, parent, instance); + return handlerToUse->CreateResource(&node, parent, instance); } } - else if (node->GetName() == wxT("object")) + else if (node.GetName() == wxT("object")) { for ( wxVector::iterator h = m_handlers.begin(); h != m_handlers.end(); ++h ) { wxXmlResourceHandler *handler = *h; - if (handler->CanHandle(node)) - return handler->CreateResource(node, parent, instance); + if (handler->CanHandle(&node)) + return handler->CreateResource(&node, parent, instance); } } ReportError ( - node, + &node, wxString::Format ( "no handler found for XML node \"%s\" (class \"%s\")", - node->GetName(), - node->GetAttribute("class", wxEmptyString) + node.GetName(), + node.GetAttribute("class", wxEmptyString) ) ); return NULL; @@ -1883,8 +1896,8 @@ void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only) { if ( IsObjectNode(n) ) { - m_resource->CreateResFromNode(n, parent, NULL, - this_hnd_only ? this : NULL); + m_resource->DoCreateResFromNode(*n, parent, NULL, + this_hnd_only ? this : NULL); } } } -- 2.45.2