From 23239d944abef634f7816a501d2daa02815842f6 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 22 Feb 2009 21:52:00 +0000 Subject: [PATCH] add public wxXmlResource::GetResourceNode() which can be used directly instead of deriving from wxXmlResource and using FindResource() git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59096 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/xrc/xmlres.h | 42 ++++++++++++-- interface/wx/xrc/xmlres.h | 20 +++++++ src/xrc/xmlres.cpp | 116 +++++++++++++++++++++++++------------- 4 files changed, 136 insertions(+), 43 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 164e7680fa..0982ebe987 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -357,6 +357,7 @@ All: - Added wxStrnlen() for safe computation of string length. - Added wxImage::Clear() (troelsk). - Added wxLog::Log(). +- Added wxXmlResource::GetResourceNode(). All (Unix): diff --git a/include/wx/xrc/xmlres.h b/include/wx/xrc/xmlres.h index 7d29dd260d..c15202e8a7 100644 --- a/include/wx/xrc/xmlres.h +++ b/include/wx/xrc/xmlres.h @@ -227,7 +227,7 @@ public: { return GetVersion() - (major*256*256*256 + minor*256*256 + release*256 + revision); } -//// Singleton accessors. + //// Singleton accessors. // Gets the global resources object or creates one if none exists. static wxXmlResource *Get(); @@ -245,16 +245,48 @@ public: const wxString& GetDomain() const { return m_domain; } void SetDomain(const wxString& domain); + + // This function returns the wxXmlNode containing the definition of the + // object with the given name or NULL. + // + // It can be used to access additional information defined in the XRC file + // and not used by wxXmlResource itself. + const wxXmlNode *GetResourceNode(const wxString& name) const + { return GetResourceNodeAndLocation(name, wxString(), true); } + protected: // Scans the resources list for unloaded files and loads them. Also reloads // files that have been modified since last loading. bool UpdateResources(); - // Finds a resource (calls UpdateResources) and returns a node containing it. - wxXmlNode *FindResource(const wxString& name, const wxString& classname, bool recursive = false); - // Helper function: finds a resource (calls UpdateResources) and returns a node containing it. - wxXmlNode *DoFindResource(wxXmlNode *parent, const wxString& name, const wxString& classname, bool recursive); + // Common implementation of GetResourceNode() and FindResource(): searches + // all top-level or all (if recursive == true) nodes if all loaded XRC + // files and returns the node, if found, as well as the path of the file it + // was found in if path is non-NULL + wxXmlNode *GetResourceNodeAndLocation(const wxString& name, + const wxString& classname, + bool recursive = false, + wxString *path = NULL) const; + + + // Note that these functions are used outside of wxWidgets itself, e.g. + // there are several known cases of inheriting from wxXmlResource just to + // be able to call FindResource() so we keep them for compatibility even if + // their names are not really consistent with GetResourceNode() public + // function and FindResource() is also non-const because it changes the + // current path of m_curFileSystem to ensure that relative paths work + // correctly when CreateResFromNode() is called immediately afterwards + // (something const public function intentionally does not do) + + // Returns the node containing the resource with the given name and class + // name unless it's empty (then any class matches) or NULL if not found. + wxXmlNode *FindResource(const wxString& name, const wxString& classname, + bool recursive = false); + + // Helper function used by FindResource() to look under the given node. + wxXmlNode *DoFindResource(wxXmlNode *parent, const wxString& name, + const wxString& classname, bool recursive) const; // Creates a resource from information in the given node // (Uses only 'handlerToUse' if != NULL) diff --git a/interface/wx/xrc/xmlres.h b/interface/wx/xrc/xmlres.h index 49f7e94c99..41fdb748eb 100644 --- a/interface/wx/xrc/xmlres.h +++ b/interface/wx/xrc/xmlres.h @@ -142,6 +142,26 @@ public: */ int GetFlags() const; + /** + Returns the wxXmlNode containing the definition of the object with the + given name or @NULL. + + This function recursively searches all the loaded XRC files for an + object with the specified @a name. If the object is found, the + wxXmlNode corresponding to it is returned, so this function can be used + to access additional information defined in the XRC file and not used + by wxXmlResource itself, e.g. contents of application-specific XML + tags. + + @param name + The name of the resource which must be unique for this function to + work correctly, if there is more than one resource with the given + name the choice of the one returned by this function is undefined. + @return + The node corresponding to the resource with the given name or @NULL. + */ + const wxXmlNode *GetResourceNode(const wxString& name) const; + /** Returns version information (a.b.c.d = d + 256*c + 2562*b + 2563*a). */ diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp index ae88b74358..65cc83c85e 100644 --- a/src/xrc/xmlres.cpp +++ b/src/xrc/xmlres.cpp @@ -70,6 +70,22 @@ class wxXmlResourceDataRecords : public wxVector // this is a class so that it can be forward-declared }; +namespace +{ + +// helper used by DoFindResource() and elsewhere: returns true if this is an +// object or object_ref node +// +// node must be non-NULL +inline bool IsObjectNode(wxXmlNode *node) +{ + return node->GetType() == wxXML_ELEMENT_NODE && + (node->GetName() == wxS("object") || + node->GetName() == wxS("object_ref")); +} + +} // anonymous namespace + wxXmlResource *wxXmlResource::ms_instance = NULL; @@ -551,86 +567,114 @@ bool wxXmlResource::UpdateResources() return rt; } - wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent, const wxString& name, const wxString& classname, - bool recursive) + bool recursive) const { - wxString dummy; wxXmlNode *node; // first search for match at the top-level nodes (as this is // where the resource is most commonly looked for): for (node = parent->GetChildren(); node; node = node->GetNext()) { - if ( node->GetType() == wxXML_ELEMENT_NODE && - (node->GetName() == wxT("object") || - node->GetName() == wxT("object_ref")) && - node->GetAttribute(wxT("name"), &dummy) && dummy == name ) + if ( IsObjectNode(node) && node->GetAttribute(wxS("name")) == name ) { - wxString cls(node->GetAttribute(wxT("class"), wxEmptyString)); - if (!classname || cls == classname) + // empty class name matches everything + if ( classname.empty() ) return node; + + wxString cls(node->GetAttribute(wxS("class"))); + // object_ref may not have 'class' attribute: - if (cls.empty() && node->GetName() == wxT("object_ref")) + if (cls.empty() && node->GetName() == wxS("object_ref")) { - wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString); + wxString refName = node->GetAttribute(wxS("ref")); if (refName.empty()) continue; - wxXmlNode* refNode = FindResource(refName, wxEmptyString, true); - if (refNode && - refNode->GetAttribute(wxT("class"), wxEmptyString) == classname) - { - return node; - } + + const wxXmlNode * const refNode = GetResourceNode(refName); + if ( refNode ) + cls = refNode->GetAttribute(wxS("class")); } + + if ( cls == classname ) + return node; } } + // then recurse in child nodes if ( recursive ) + { for (node = parent->GetChildren(); node; node = node->GetNext()) { - if ( node->GetType() == wxXML_ELEMENT_NODE && - (node->GetName() == wxT("object") || - node->GetName() == wxT("object_ref")) ) + if ( IsObjectNode(node) ) { wxXmlNode* found = DoFindResource(node, name, classname, true); if ( found ) return found; } } + } - return NULL; + return NULL; } wxXmlNode *wxXmlResource::FindResource(const wxString& name, const wxString& classname, bool recursive) { - UpdateResources(); //ensure everything is up-to-date + wxString path; + wxXmlNode * const + node = GetResourceNodeAndLocation(name, classname, recursive, &path); + + if ( !node ) + { + wxLogError(_("XRC resource '%s' (class '%s') not found!"), + name, classname); + } +#if wxUSE_FILESYSTEM + else // node was found + { + // ensure that relative paths work correctly when loading this node + // (which should happen as soon as we return as FindResource() result + // is always passed to CreateResFromNode()) + m_curFileSystem.ChangePathTo(path); + } +#endif // wxUSE_FILESYSTEM + + return node; +} + +wxXmlNode * +wxXmlResource::GetResourceNodeAndLocation(const wxString& name, + const wxString& classname, + bool recursive, + wxString *path) const +{ + // ensure everything is up-to-date: this is needed to support on-remand + // reloading of XRC files + const_cast(this)->UpdateResources(); - wxString dummy; for ( wxXmlResourceDataRecords::const_iterator f = Data().begin(); f != Data().end(); ++f ) { - wxXmlResourceDataRecord* const rec = *f; - if ( rec->Doc == NULL || rec->Doc->GetRoot() == NULL ) + wxXmlResourceDataRecord *const rec = *f; + wxXmlDocument * const doc = rec->Doc; + if ( !doc || !doc->GetRoot() ) continue; - wxXmlNode* found = DoFindResource(rec->Doc->GetRoot(), - name, classname, recursive); + wxXmlNode * const + found = DoFindResource(doc->GetRoot(), name, classname, recursive); if ( found ) { -#if wxUSE_FILESYSTEM - m_curFileSystem.ChangePathTo(rec->File); -#endif + if ( path ) + *path = rec->File; + return found; } } - wxLogError(_("XRC resource '%s' (class '%s') not found!"), - name.c_str(), classname.c_str()); return NULL; } @@ -1518,17 +1562,13 @@ void wxXmlResourceHandler::SetupWindow(wxWindow *wnd) void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only) { - wxXmlNode *n = m_node->GetChildren(); - - while (n) + for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() ) { - if (n->GetType() == wxXML_ELEMENT_NODE && - (n->GetName() == wxT("object") || n->GetName() == wxT("object_ref"))) + if ( IsObjectNode(n) ) { m_resource->CreateResFromNode(n, parent, NULL, this_hnd_only ? this : NULL); } - n = n->GetNext(); } } -- 2.47.2