Add wxXmlResource::LoadDocument()

This allows loading XRC from anywhere, not just files and URLs.
This commit is contained in:
Vadim Zeitlin
2021-04-14 23:59:39 +01:00
parent db3e54b3dc
commit c16082edfe
3 changed files with 129 additions and 7 deletions

View File

@@ -131,6 +131,13 @@ public:
// Loads all XRC files from a directory. // Loads all XRC files from a directory.
bool LoadAllFiles(const wxString& dirname); bool LoadAllFiles(const wxString& dirname);
// Loads resources from the given XML document, taking ownership of it.
//
// The name argument is only used to Unload() the document later here and
// doesn't need to be an existing filename at all (but should be unique if
// specified, otherwise it's just synthesized internally).
bool LoadDocument(wxXmlDocument* doc, const wxString& name = wxString());
// Unload resource from the given XML file (wildcards not allowed) // Unload resource from the given XML file (wildcards not allowed)
bool Unload(const wxString& filename); bool Unload(const wxString& filename);
@@ -320,6 +327,9 @@ protected:
// wxXmlDocument (which will be owned by caller) on success or NULL. // wxXmlDocument (which will be owned by caller) on success or NULL.
wxXmlDocument *DoLoadFile(const wxString& file); wxXmlDocument *DoLoadFile(const wxString& file);
// Load XRC from the given document and returns true on success.
bool DoLoadDocument(const wxXmlDocument& doc);
// Scans the resources list for unloaded files and loads them. Also reloads // Scans the resources list for unloaded files and loads them. Also reloads
// files that have been modified since last loading. // files that have been modified since last loading.
bool UpdateResources(); bool UpdateResources();

View File

@@ -233,12 +233,58 @@ public:
*/ */
bool Load(const wxString& filemask); bool Load(const wxString& filemask);
/**
Load resources from the XML document containing them.
This can be useful when XRC contents comes from some place other than a
file or, more generally, an URL, as it can still be read into a
wxMemoryInputStream and then wxXmlDocument can be created from this
stream and used with this function.
For example:
@code
const char* const xrc_data = ...; // Retrieve it from wherever.
wxMemoryInputStream mis(xrc_data, strlen(xrc_data));
wxScopedPtr<wxXmlDocument> xmlDoc(new wxXmlDocument(mis, "UTF-8"));
if ( !xmlDoc->IsOk() )
{
... handle invalid XML here ...
return;
}
if ( !wxXmlResource::Get()->LoadDocument(xmlDoc.release()) )
{
... handle invalid XRC here ...
return;
}
... use the just loaded XRC as usual ...
@endcode
@param doc A valid, i.e. non-null, document pointer ownership of which
is passed to wxXmlResource, i.e. this pointer can't be used after
this function rteturns.
@param name The name argument is optional, but may be provided if you
plan to call Unload() later. It doesn't need to be an existing file
or even conform to the usual form of file names as it is not
interpreted in any way by wxXmlResource, but it should be unique
among the other documents and file names used if specified.
@return @true on success, @false if the document couldn't be loaded
(note that @a doc is still destroyed in this case to avoid memory
leaks).
@see Load(), LoadFile()
@since 3.1.6
*/
bool LoadDocument(wxXmlDocument* doc, const wxString& name = wxString());
/** /**
Simpler form of Load() for loading a single XRC file. Simpler form of Load() for loading a single XRC file.
@since 2.9.0 @since 2.9.0
@see Load(), LoadAllFiles() @see Load(), LoadAllFiles(), LoadDocument()
*/ */
bool LoadFile(const wxFileName& file); bool LoadFile(const wxFileName& file);

View File

@@ -74,17 +74,43 @@ wxDateTime GetXRCFileModTime(const wxString& filename)
// name. // name.
static void XRCID_Assign(const wxString& str_id, int value); static void XRCID_Assign(const wxString& str_id, int value);
// Flags indicating whether the XRC contents was loaded from file or URL, more
// generally: this is usually true but is not set for the records created
// directly from wxXmlDocument.
namespace XRCWhence
{
enum
{
From_URL = 0,
From_Doc = 1
};
} // namespace // XRCWhence
class wxXmlResourceDataRecord class wxXmlResourceDataRecord
{ {
public: public:
// Ctor takes ownership of the document pointer. // Ctor takes ownership of the document pointer.
wxXmlResourceDataRecord(const wxString& File_, wxXmlResourceDataRecord(const wxString& File_,
wxXmlDocument *Doc_ wxXmlDocument *Doc_,
int flags = XRCWhence::From_URL
) )
: File(File_), Doc(Doc_) : File(File_), Doc(Doc_)
{ {
#if wxUSE_DATETIME #if wxUSE_DATETIME
switch ( flags )
{
case XRCWhence::From_URL:
Time = GetXRCFileModTime(File); Time = GetXRCFileModTime(File);
break;
case XRCWhence::From_Doc:
// Leave Time invalid.
break;
}
#else
wxUnusedVar(flags);
#endif #endif
} }
@@ -664,9 +690,14 @@ bool wxXmlResource::UpdateResources()
if ( m_flags & wxXRC_NO_RELOADING ) if ( m_flags & wxXRC_NO_RELOADING )
continue; continue;
// And we don't do it for the records that were not loaded from a
// file/URI (or at least not directly) in the first place.
if ( !rec->Time.IsValid() )
continue;
// Otherwise check its modification time if we can. // Otherwise check its modification time if we can.
#if wxUSE_DATETIME #if wxUSE_DATETIME
const wxDateTime lastModTime = GetXRCFileModTime(rec->File); wxDateTime lastModTime = GetXRCFileModTime(rec->File);
if ( lastModTime.IsValid() && lastModTime <= rec->Time ) if ( lastModTime.IsValid() && lastModTime <= rec->Time )
#else // !wxUSE_DATETIME #else // !wxUSE_DATETIME
@@ -749,7 +780,15 @@ wxXmlDocument *wxXmlResource::DoLoadFile(const wxString& filename)
return NULL; return NULL;
} }
wxXmlNode * const root = doc->GetRoot(); if (!DoLoadDocument(*doc))
return NULL;
return doc.release();
}
bool wxXmlResource::DoLoadDocument(const wxXmlDocument& doc)
{
wxXmlNode * const root = doc.GetRoot();
if (root->GetName() != wxT("resource")) if (root->GetName() != wxT("resource"))
{ {
ReportError ReportError
@@ -757,7 +796,7 @@ wxXmlDocument *wxXmlResource::DoLoadFile(const wxString& filename)
root, root,
"invalid XRC resource, doesn't have root node <resource>" "invalid XRC resource, doesn't have root node <resource>"
); );
return NULL; return false;
} }
long version; long version;
@@ -778,7 +817,34 @@ wxXmlDocument *wxXmlResource::DoLoadFile(const wxString& filename)
PreprocessForIdRanges(root); PreprocessForIdRanges(root);
wxIdRangeManager::Get()->FinaliseRanges(root); wxIdRangeManager::Get()->FinaliseRanges(root);
return doc.release(); return true;
}
bool wxXmlResource::LoadDocument(wxXmlDocument* doc, const wxString& name)
{
wxCHECK_MSG( doc, false, wxS("must have a valid document") );
if ( !DoLoadDocument(*doc) )
{
// Still avoid memory leaks.
delete doc;
return false;
}
// We need to use something instead of the file name, so if we were not
// given a name synthesize something ourselves.
wxString docname = name;
if ( docname.empty() )
{
static unsigned long s_xrcDocument = 0;
// Make it look different from any real file name.
docname = wxString::Format(wxS("<XML document #%lu>"), ++s_xrcDocument);
}
Data().push_back(new wxXmlResourceDataRecord(docname, doc, XRCWhence::From_Doc));
return true;
} }
wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent, wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,