]> git.saurik.com Git - wxWidgets.git/blobdiff - src/xrc/xmlres.cpp
Fix history in wxWebViewIE when using a custom file scheme.
[wxWidgets.git] / src / xrc / xmlres.cpp
index c6683a31788afaa7528b4308bc4c344542829d98..95525ac90a0af2e8850cc73b58a85ac8fcd5506e 100644 (file)
 #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<wxFSFile> 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<wxXmlResourceDataRecord*>
@@ -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 <resource>"
-                );
-                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<wxFSFile> 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<wxXmlDocument> 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 <resource>"
+        );
+        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, <object_ref> 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;
     }
 }