X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d807030e1eccc4ac1a7c434968fef654ea8bf38e..d2e66707deb10dea6f92e3e4092f8a43ef942a5d:/src/xrc/xmlres.cpp diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp index c6683a3178..95525ac90a 100644 --- a/src/xrc/xmlres.cpp +++ b/src/xrc/xmlres.cpp @@ -48,16 +48,45 @@ #include "wx/dir.h" #include "wx/xml/xml.h" #include "wx/hashset.h" +#include "wx/scopedptr.h" +namespace +{ + +// Helper function to get modification time of either a wxFileSystem URI or +// just a normal file name, depending on the build. +#if wxUSE_DATETIME + +wxDateTime GetXRCFileModTime(const wxString& filename) +{ +#if wxUSE_FILESYSTEM + wxFileSystem fsys; + wxScopedPtr file(fsys.OpenFile(filename)); + + return file ? file->GetModificationTime() : wxDateTime(); +#else // wxUSE_FILESYSTEM + return wxDateTime(wxFileModificationTime(filename)); +#endif // wxUSE_FILESYSTEM +} + +#endif // wxUSE_DATETIME + +} // anonymous namespace class wxXmlResourceDataRecord { public: - wxXmlResourceDataRecord() : Doc(NULL) { + // Ctor takes ownership of the document pointer. + wxXmlResourceDataRecord(const wxString& File_, + wxXmlDocument *Doc_ + ) + : File(File_), Doc(Doc_) + { #if wxUSE_DATETIME - Time = wxDateTime::Now(); + Time = GetXRCFileModTime(File); #endif } + ~wxXmlResourceDataRecord() {delete Doc;} wxString File; @@ -65,6 +94,8 @@ public: #if wxUSE_DATETIME wxDateTime Time; #endif + + wxDECLARE_NO_COPY_CLASS(wxXmlResourceDataRecord); }; class wxXmlResourceDataRecords : public wxVector @@ -123,7 +154,7 @@ public: int Find(const wxString& rangename) const; // Removes, if it exists, an entry from the XRCID table. Used in id-ranges // to replace defunct or statically-initialised entries with current values - static void RemoveXRCIDEntry(const char *str_id); + static void RemoveXRCIDEntry(const wxString& idstr); protected: wxIdRange* FindRangeForItem(const wxXmlNode* node, @@ -314,6 +345,8 @@ bool wxXmlResource::Load(const wxString& filemask_) { wxString filemask = ConvertFileNameToURL(filemask_); + bool allOK = true; + #if wxUSE_FILESYSTEM wxFileSystem fsys; # define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE) @@ -335,14 +368,16 @@ bool wxXmlResource::Load(const wxString& filemask_) if ( IsArchive(fnd) ) { if ( !Load(fnd + wxT("#zip:*.xrc")) ) - return false; + allOK = false; } else // a single resource URL #endif // wxUSE_FILESYSTEM { - wxXmlResourceDataRecord *drec = new wxXmlResourceDataRecord; - drec->File = fnd; - Data().push_back(drec); + wxXmlDocument * const doc = DoLoadFile(fnd); + if ( !doc ) + allOK = false; + else + Data().push_back(new wxXmlResourceDataRecord(fnd, doc)); } fnd = wxXmlFindNext; @@ -350,7 +385,7 @@ bool wxXmlResource::Load(const wxString& filemask_) # undef wxXmlFindFirst # undef wxXmlFindNext - return UpdateResources(); + return allOK; } bool wxXmlResource::Unload(const wxString& filename) @@ -613,133 +648,133 @@ static void PreprocessForIdRanges(wxXmlNode *rootnode) bool wxXmlResource::UpdateResources() { bool rt = true; - bool modif; -# if wxUSE_FILESYSTEM - wxFSFile *file = NULL; - wxUnusedVar(file); - wxFileSystem fsys; -# endif - - wxString encoding(wxT("UTF-8")); -#if !wxUSE_UNICODE && wxUSE_INTL - if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 ) - { - // In case we are not using wxLocale to translate strings, convert the - // strings GUI's charset. This must not be done when wxXRC_USE_LOCALE - // is on, because it could break wxGetTranslation lookup. - encoding = wxLocale::GetSystemEncodingName(); - } -#endif for ( wxXmlResourceDataRecords::iterator i = Data().begin(); i != Data().end(); ++i ) { wxXmlResourceDataRecord* const rec = *i; - modif = (rec->Doc == NULL); + // Check if we need to reload this one. + + // We never do it if this flag is specified. + if ( m_flags & wxXRC_NO_RELOADING ) + continue; - if (!modif && !(m_flags & wxXRC_NO_RELOADING)) + // Otherwise check its modification time if we can. +#if wxUSE_DATETIME + const wxDateTime lastModTime = GetXRCFileModTime(rec->File); + + if ( lastModTime.IsValid() && lastModTime <= rec->Time ) +#else // !wxUSE_DATETIME + // Never reload the file contents: we can't know whether it changed or + // not in this build configuration and it would be unexpected and + // counter-productive to get a performance hit (due to constant + // reloading of XRC files) in a minimal wx build which is presumably + // used because of resource constraints of the current platform. +#endif // wxUSE_DATETIME/!wxUSE_DATETIME { -# if wxUSE_FILESYSTEM - file = fsys.OpenFile(rec->File); -# if wxUSE_DATETIME - modif = file && file->GetModificationTime() > rec->Time; -# else // wxUSE_DATETIME - modif = true; -# endif // wxUSE_DATETIME - if (!file) - { - wxLogError(_("Cannot open file '%s'."), rec->File); - rt = false; - } - wxDELETE(file); - wxUnusedVar(file); -# else // wxUSE_FILESYSTEM -# if wxUSE_DATETIME - modif = wxDateTime(wxFileModificationTime(rec->File)) > rec->Time; -# else // wxUSE_DATETIME - modif = true; -# endif // wxUSE_DATETIME -# endif // wxUSE_FILESYSTEM + // No need to reload, the file wasn't modified since we did it + // last. + continue; } - if (modif) + wxXmlDocument * const doc = DoLoadFile(rec->File); + if ( !doc ) { - wxLogTrace(wxT("xrc"), wxT("opening file '%s'"), rec->File); + // Notice that we keep the old XML document: it seems better to + // preserve it instead of throwing it away if we have nothing to + // replace it with. + rt = false; + continue; + } - wxInputStream *stream = NULL; + // Replace the old resource contents with the new one. + delete rec->Doc; + rec->Doc = doc; -# if wxUSE_FILESYSTEM - file = fsys.OpenFile(rec->File); - if (file) - stream = file->GetStream(); -# else - stream = new wxFileInputStream(rec->File); -# endif + // And, now that we loaded it successfully, update the last load time. +#if wxUSE_DATETIME + rec->Time = lastModTime.IsValid() ? lastModTime : wxDateTime::Now(); +#endif // wxUSE_DATETIME + } - if (stream) - { - delete rec->Doc; - rec->Doc = new wxXmlDocument; - } - if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding)) - { - wxLogError(_("Cannot load resources from file '%s'."), - rec->File); - wxDELETE(rec->Doc); - rt = false; - } - else if (rec->Doc->GetRoot()->GetName() != wxT("resource")) - { - ReportError - ( - rec->Doc->GetRoot(), - "invalid XRC resource, doesn't have root node " - ); - wxDELETE(rec->Doc); - rt = false; - } - else - { - long version; - int v1, v2, v3, v4; - wxString verstr = rec->Doc->GetRoot()->GetAttribute( - wxT("version"), wxT("0.0.0.0")); - if (wxSscanf(verstr.c_str(), wxT("%i.%i.%i.%i"), - &v1, &v2, &v3, &v4) == 4) - version = v1*256*256*256+v2*256*256+v3*256+v4; - else - version = 0; - if (m_version == -1) - m_version = version; - if (m_version != version) - { - wxLogError("Resource files must have same version number."); - rt = false; - } + return rt; +} + +wxXmlDocument *wxXmlResource::DoLoadFile(const wxString& filename) +{ + wxLogTrace(wxT("xrc"), wxT("opening file '%s'"), filename); + + wxInputStream *stream = NULL; - ProcessPlatformProperty(rec->Doc->GetRoot()); - PreprocessForIdRanges(rec->Doc->GetRoot()); - wxIdRangeManager::Get()->FinaliseRanges(rec->Doc->GetRoot()); -#if wxUSE_DATETIME #if wxUSE_FILESYSTEM - rec->Time = file->GetModificationTime(); -#else // wxUSE_FILESYSTEM - rec->Time = wxDateTime(wxFileModificationTime(rec->File)); -#endif // wxUSE_FILESYSTEM -#endif // wxUSE_DATETIME - } + wxFileSystem fsys; + wxScopedPtr file(fsys.OpenFile(filename)); + if (file) + { + // Notice that we don't have ownership of the stream in this case, it + // remains owned by wxFSFile. + stream = file->GetStream(); + } +#else // !wxUSE_FILESYSTEM + wxFileInputStream fstream(filename); + stream = &fstream; +#endif // wxUSE_FILESYSTEM/!wxUSE_FILESYSTEM -# if wxUSE_FILESYSTEM - wxDELETE(file); - wxUnusedVar(file); -# else - wxDELETE(stream); -# endif - } + if ( !stream || !stream->IsOk() ) + { + wxLogError(_("Cannot open resources file '%s'."), filename); + return NULL; } - return rt; + wxString encoding(wxT("UTF-8")); +#if !wxUSE_UNICODE && wxUSE_INTL + if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 ) + { + // In case we are not using wxLocale to translate strings, convert the + // strings GUI's charset. This must not be done when wxXRC_USE_LOCALE + // is on, because it could break wxGetTranslation lookup. + encoding = wxLocale::GetSystemEncodingName(); + } +#endif + + wxScopedPtr doc(new wxXmlDocument); + if (!doc->Load(*stream, encoding)) + { + wxLogError(_("Cannot load resources from file '%s'."), filename); + return NULL; + } + + wxXmlNode * const root = doc->GetRoot(); + if (root->GetName() != wxT("resource")) + { + ReportError + ( + root, + "invalid XRC resource, doesn't have root node " + ); + return NULL; + } + + long version; + int v1, v2, v3, v4; + wxString verstr = root->GetAttribute(wxT("version"), wxT("0.0.0.0")); + if (wxSscanf(verstr, wxT("%i.%i.%i.%i"), &v1, &v2, &v3, &v4) == 4) + version = v1*256*256*256+v2*256*256+v3*256+v4; + else + version = 0; + if (m_version == -1) + m_version = version; + if (m_version != version) + { + wxLogWarning("Resource files must have same version number."); + } + + ProcessPlatformProperty(root); + PreprocessForIdRanges(root); + wxIdRangeManager::Get()->FinaliseRanges(root); + + return doc.release(); } wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent, @@ -948,7 +983,10 @@ wxXmlResource::DoCreateResFromNode(wxXmlNode& node, return NULL; } - if ( !node.GetChildren() ) + const bool hasOnlyRefAttr = node.GetAttributes() != NULL && + node.GetAttributes()->GetNext() == NULL; + + if ( hasOnlyRefAttr && !node.GetChildren() ) { // In the typical, simple case, is used to link // to another node and doesn't have any content of its own that @@ -1185,9 +1223,11 @@ void wxIdRange::Finalise(const wxXmlNode* node) // Use the second parameter of GetXRCID to force it to take the value i wxXmlResource::GetXRCID(m_name + wxString::Format("[%i]", i-m_start), i); - wxLogTrace("xrcrange","integer = %i %s now returns %i", i, - m_name + wxString::Format("[%i]", i-m_start).mb_str(), - XRCID(m_name + wxString::Format("[%i]", i-m_start).mb_str())); + wxLogTrace("xrcrange", + "integer = %i %s now returns %i", + i, + m_name + wxString::Format("[%i]", i-m_start), + XRCID((m_name + wxString::Format("[%i]", i-m_start)).mb_str())); } // and these special ones wxIdRangeManager::RemoveXRCIDEntry(m_name + "[start]"); @@ -1705,7 +1745,7 @@ wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& // the colour doesn't use #RRGGBB format, check if it is symbolic // colour name: clr = GetSystemColour(v); - if (clr.Ok()) + if (clr.IsOk()) return clr; ReportParamError @@ -1783,7 +1823,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node, art_id, art_client) ) { wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size)); - if ( stockArt.Ok() ) + if ( stockArt.IsOk() ) return stockArt; } @@ -1807,7 +1847,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node, wxImage img(name); #endif - if (!img.Ok()) + if (!img.IsOk()) { ReportParamError ( @@ -1921,7 +1961,7 @@ wxImageList *wxXmlResourceHandler::GetImageList(const wxString& param) { if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == parambitmap) { - wxIcon icon = GetIcon(n); + wxIcon icon = GetIcon(n, wxART_OTHER, size); if ( !imagelist ) { // We need the real image list size to create it. @@ -2237,7 +2277,7 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) // is this font based on a system font? wxFont font = GetSystemFont(GetParamValue(wxT("sysfont"))); - if (font.Ok()) + if (font.IsOk()) { if (hasSize && isize != -1) font.SetPointSize(isize); @@ -2627,8 +2667,10 @@ wxString wxXmlResource::FindXRCIDById(int numId) } /* static */ -void wxIdRangeManager::RemoveXRCIDEntry(const char *str_id) +void wxIdRangeManager::RemoveXRCIDEntry(const wxString& idstr) { + const char *str_id = idstr.mb_str(); + const unsigned index = XRCIdHash(str_id); XRCID_record **p_previousrec = &XRCID_Records[index]; @@ -2637,16 +2679,14 @@ void wxIdRangeManager::RemoveXRCIDEntry(const char *str_id) if (wxStrcmp(rec->key, str_id) == 0) { // Found the item to be removed so delete its record; but first - // replace it in the table with any rec->next (usually == NULL) - (*p_previousrec) = rec->next; + // remove it from the linked list. + *p_previousrec = rec->next; free(rec->key); delete rec; return; } - else - { - p_previousrec = &rec; - } + + p_previousrec = &rec->next; } }