]> git.saurik.com Git - wxWidgets.git/blobdiff - src/xrc/xmlres.cpp
added multiple selections support to wxDirCtrl (closes #10830)
[wxWidgets.git] / src / xrc / xmlres.cpp
index efee9e17e5ac5336510610f6dec9a134564b0eea..d19bdec665be788d32ba1d9a95a338dea5dc001e 100644 (file)
@@ -44,7 +44,8 @@
 #include "wx/fontenum.h"
 #include "wx/fontmap.h"
 #include "wx/artprov.h"
 #include "wx/fontenum.h"
 #include "wx/fontmap.h"
 #include "wx/artprov.h"
-
+#include "wx/imaglist.h"
+#include "wx/dir.h"
 #include "wx/xml/xml.h"
 
 
 #include "wx/xml/xml.h"
 
 
@@ -70,6 +71,64 @@ class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord*>
     // this is a class so that it can be forward-declared
 };
 
     // 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"));
+}
+
+// special XML attribute with name of input file, see GetFileNameFromNode()
+const char *ATTR_INPUT_FILENAME = "__wx:filename";
+
+// helper to get filename corresponding to an XML node
+wxString
+GetFileNameFromNode(wxXmlNode *node, const wxXmlResourceDataRecords& files)
+{
+    // this loop does two things: it looks for ATTR_INPUT_FILENAME among
+    // parents and if it isn't used, it finds the root of the XML tree 'node'
+    // is in
+    for ( ;; )
+    {
+        // in some rare cases (specifically, when an <object_ref> is used, see
+        // wxXmlResource::CreateResFromNode() and MergeNodesOver()), we work
+        // with XML nodes that are not rooted in any document from 'files'
+        // (because a new node was created by CreateResFromNode() to merge the
+        // content of <object_ref> and the referenced <object>); in that case,
+        // we hack around the problem by putting the information about input
+        // file into a custom attribute
+        if ( node->HasAttribute(ATTR_INPUT_FILENAME) )
+            return node->GetAttribute(ATTR_INPUT_FILENAME);
+
+        if ( !node->GetParent() )
+            break; // we found the root of this XML tree
+
+        node = node->GetParent();
+    }
+
+    // NB: 'node' now points to the root of XML document
+
+    for ( wxXmlResourceDataRecords::const_iterator i = files.begin();
+          i != files.end(); ++i )
+    {
+        if ( (*i)->Doc->GetRoot() == node )
+        {
+            return (*i)->File;
+        }
+    }
+
+    return wxEmptyString; // not found
+}
+
+} // anonymous namespace
+
 
 wxXmlResource *wxXmlResource::ms_instance = NULL;
 
 
 wxXmlResource *wxXmlResource::ms_instance = NULL;
 
@@ -162,8 +221,35 @@ bool wxXmlResource::IsArchive(const wxString& filename)
 
 #endif // wxUSE_FILESYSTEM
 
 
 #endif // wxUSE_FILESYSTEM
 
-bool wxXmlResource::Load(const wxString& filemask)
+bool wxXmlResource::LoadFile(const wxFileName& file)
 {
 {
+#if wxUSE_FILESYSTEM
+    return Load(wxFileSystem::FileNameToURL(file));
+#else
+    return Load(file.GetFullPath());
+#endif
+}
+
+bool wxXmlResource::LoadAllFiles(const wxString& dirname)
+{
+    bool ok = true;
+    wxArrayString files;
+
+    wxDir::GetAllFiles(dirname, &files, "*.xrc");
+
+    for ( wxArrayString::const_iterator i = files.begin(); i != files.end(); ++i )
+    {
+        if ( !LoadFile(*i) )
+            ok = false;
+    }
+
+    return ok;
+}
+
+bool wxXmlResource::Load(const wxString& filemask_)
+{
+    wxString filemask = ConvertFileNameToURL(filemask_);
+
 #if wxUSE_FILESYSTEM
     wxFileSystem fsys;
 #   define wxXmlFindFirst  fsys.FindFirst(filemask, wxFILE)
 #if wxUSE_FILESYSTEM
     wxFileSystem fsys;
 #   define wxXmlFindFirst  fsys.FindFirst(filemask, wxFILE)
@@ -181,8 +267,6 @@ bool wxXmlResource::Load(const wxString& filemask)
 
     while (!fnd.empty())
     {
 
     while (!fnd.empty())
     {
-        fnd = ConvertFileNameToURL(fnd);
-
 #if wxUSE_FILESYSTEM
         if ( IsArchive(fnd) )
         {
 #if wxUSE_FILESYSTEM
         if ( IsArchive(fnd) )
         {
@@ -366,7 +450,7 @@ bool wxXmlResource::AttachUnknownControl(const wxString& name,
     wxWindow *container = parent->FindWindow(name + wxT("_container"));
     if (!container)
     {
     wxWindow *container = parent->FindWindow(name + wxT("_container"));
     if (!container)
     {
-        wxLogError(_("Cannot find container for unknown control '%s'."), name.c_str());
+        wxLogError("Cannot find container for unknown control '%s'.", name);
         return false;
     }
     return control->Reparent(container);
         return false;
     }
     return control->Reparent(container);
@@ -497,7 +581,7 @@ bool wxXmlResource::UpdateResources()
                 delete rec->Doc;
                 rec->Doc = new wxXmlDocument;
             }
                 delete rec->Doc;
                 rec->Doc = new wxXmlDocument;
             }
-            if (!stream || !rec->Doc->Load(*stream, encoding))
+            if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding))
             {
                 wxLogError(_("Cannot load resources from file '%s'."),
                            rec->File);
             {
                 wxLogError(_("Cannot load resources from file '%s'."),
                            rec->File);
@@ -506,7 +590,11 @@ bool wxXmlResource::UpdateResources()
             }
             else if (rec->Doc->GetRoot()->GetName() != wxT("resource"))
             {
             }
             else if (rec->Doc->GetRoot()->GetName() != wxT("resource"))
             {
-                wxLogError(_("Invalid XRC resource '%s': doesn't have root node 'resource'."), rec->File);
+                ReportError
+                (
+                    rec->Doc->GetRoot(),
+                    "invalid XRC resource, doesn't have root node <resource>"
+                );
                 wxDELETE(rec->Doc);
                 rt = false;
             }
                 wxDELETE(rec->Doc);
                 rt = false;
             }
@@ -525,7 +613,7 @@ bool wxXmlResource::UpdateResources()
                     m_version = version;
                 if (m_version != version)
                 {
                     m_version = version;
                 if (m_version != version)
                 {
-                    wxLogError(_("Resource files must have same version number!"));
+                    wxLogError("Resource files must have same version number.");
                     rt = false;
                 }
 
                     rt = false;
                 }
 
@@ -551,93 +639,129 @@ bool wxXmlResource::UpdateResources()
     return rt;
 }
 
     return rt;
 }
 
-
 wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,
                                          const wxString& name,
                                          const wxString& classname,
 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())
     {
     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;
                 return node;
+
+            wxString cls(node->GetAttribute(wxS("class")));
+
             // object_ref may not have 'class' attribute:
             // 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;
                 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 )
     if ( recursive )
+    {
         for (node = parent->GetChildren(); node; node = node->GetNext())
         {
         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;
             }
         }
             {
                 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)
 {
 }
 
 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 )
+    {
+        ReportError
+        (
+            NULL,
+            wxString::Format
+            (
+                "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<wxXmlResource *>(this)->UpdateResources();
 
 
-    wxString dummy;
     for ( wxXmlResourceDataRecords::const_iterator f = Data().begin();
           f != Data().end(); ++f )
     {
     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;
 
             continue;
 
-        wxXmlNode* found = DoFindResource(rec->Doc->GetRoot(),
-                                          name, classname, recursive);
+        wxXmlNode * const
+            found = DoFindResource(doc->GetRoot(), name, classname, recursive);
         if ( found )
         {
         if ( found )
         {
-#if wxUSE_FILESYSTEM
-            m_curFileSystem.ChangePathTo(rec->File);
-#endif
+            if ( path )
+                *path = rec->File;
+
             return found;
         }
     }
 
             return found;
         }
     }
 
-    wxLogError(_("XRC resource '%s' (class '%s') not found!"),
-               name.c_str(), classname.c_str());
     return NULL;
 }
 
     return NULL;
 }
 
-static void MergeNodes(wxXmlNode& dest, wxXmlNode& with)
+static void MergeNodesOver(wxXmlNode& dest, wxXmlNode& overwriteWith,
+                           const wxString& overwriteFilename)
 {
     // Merge attributes:
 {
     // Merge attributes:
-    for ( wxXmlAttribute *attr = with.GetAttributes();
+    for ( wxXmlAttribute *attr = overwriteWith.GetAttributes();
           attr; attr = attr->GetNext() )
     {
         wxXmlAttribute *dattr;
           attr; attr = attr->GetNext() )
     {
         wxXmlAttribute *dattr;
@@ -656,7 +780,7 @@ static void MergeNodes(wxXmlNode& dest, wxXmlNode& with)
    }
 
     // Merge child nodes:
    }
 
     // Merge child nodes:
-    for (wxXmlNode* node = with.GetChildren(); node; node = node->GetNext())
+    for (wxXmlNode* node = overwriteWith.GetChildren(); node; node = node->GetNext())
     {
         wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
         wxXmlNode *dnode;
     {
         wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
         wxXmlNode *dnode;
@@ -667,28 +791,32 @@ static void MergeNodes(wxXmlNode& dest, wxXmlNode& with)
                  dnode->GetAttribute(wxT("name"), wxEmptyString) == name &&
                  dnode->GetType() == node->GetType() )
             {
                  dnode->GetAttribute(wxT("name"), wxEmptyString) == name &&
                  dnode->GetType() == node->GetType() )
             {
-                MergeNodes(*dnode, *node);
+                MergeNodesOver(*dnode, *node, overwriteFilename);
                 break;
             }
         }
 
         if ( !dnode )
         {
                 break;
             }
         }
 
         if ( !dnode )
         {
+            wxXmlNode *copyOfNode = new wxXmlNode(*node);
+            // remember referenced object's file, see GetFileNameFromNode()
+            copyOfNode->AddAttribute(ATTR_INPUT_FILENAME, overwriteFilename);
+
             static const wxChar *AT_END = wxT("end");
             wxString insert_pos = node->GetAttribute(wxT("insert_at"), AT_END);
             if ( insert_pos == AT_END )
             {
             static const wxChar *AT_END = wxT("end");
             wxString insert_pos = node->GetAttribute(wxT("insert_at"), AT_END);
             if ( insert_pos == AT_END )
             {
-                dest.AddChild(new wxXmlNode(*node));
+                dest.AddChild(copyOfNode);
             }
             else if ( insert_pos == wxT("begin") )
             {
             }
             else if ( insert_pos == wxT("begin") )
             {
-                dest.InsertChild(new wxXmlNode(*node), dest.GetChildren());
+                dest.InsertChild(copyOfNode, dest.GetChildren());
             }
         }
     }
 
             }
         }
     }
 
-    if ( dest.GetType() == wxXML_TEXT_NODE && with.GetContent().length() )
-         dest.SetContent(with.GetContent());
+    if ( dest.GetType() == wxXML_TEXT_NODE && overwriteWith.GetContent().length() )
+         dest.SetContent(overwriteWith.GetContent());
 }
 
 wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
 }
 
 wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
@@ -705,15 +833,43 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
 
         if ( !refNode )
         {
 
         if ( !refNode )
         {
-            wxLogError(_("Referenced object node with ref=\"%s\" not found!"),
-                       refName.c_str());
+            ReportError
+            (
+                node,
+                wxString::Format
+                (
+                    "referenced object node with ref=\"%s\" not found",
+                    refName
+                )
+            );
             return NULL;
         }
 
             return NULL;
         }
 
-        wxXmlNode copy(*refNode);
-        MergeNodes(copy, *node);
+        if ( !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
+            // would overwrite linked object's properties. In this case,
+            // we can simply create the resource from linked node.
 
 
-        return CreateResFromNode(&copy, parent, instance);
+            return CreateResFromNode(refNode, parent, instance);
+        }
+        else
+        {
+            // In the more complicated (but rare) case, <object_ref> has
+            // subnodes that partially overwrite content of the referenced
+            // object. In this case, we need to merge both XML trees and
+            // load the resource from result of the merge.
+
+            wxXmlNode copy(*refNode);
+            MergeNodesOver(copy, *node, GetFileNameFromNode(node, Data()));
+
+            // remember referenced object's file, see GetFileNameFromNode()
+            copy.AddAttribute(ATTR_INPUT_FILENAME,
+                              GetFileNameFromNode(refNode, Data()));
+
+            return CreateResFromNode(&copy, parent, instance);
+        }
     }
 
     if (handlerToUse)
     }
 
     if (handlerToUse)
@@ -734,9 +890,16 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
         }
     }
 
         }
     }
 
-    wxLogError(_("No handler found for XML node '%s', class '%s'!"),
-               node->GetName().c_str(),
-               node->GetAttribute(wxT("class"), wxEmptyString).c_str());
+    ReportError
+    (
+        node,
+        wxString::Format
+        (
+            "no handler found for XML node \"%s\" (class \"%s\")",
+            node->GetName(),
+            node->GetAttribute("class", wxEmptyString)
+        )
+    );
     return NULL;
 }
 
     return NULL;
 }
 
@@ -808,8 +971,15 @@ wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent
             if (!m_instance)
             {
                 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
             if (!m_instance)
             {
                 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
-                wxLogError(_("Subclass '%s' not found for resource '%s', not subclassing!"),
-                           subclass.c_str(), name.c_str());
+                ReportError
+                (
+                    node,
+                    wxString::Format
+                    (
+                        "subclass \"%s\" not found for resource \"%s\", not subclassing",
+                        subclass, name
+                    )
+                );
             }
         }
     }
             }
         }
     }
@@ -883,9 +1053,17 @@ int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
         fl = tkn.GetNextToken();
         index = m_styleNames.Index(fl);
         if (index != wxNOT_FOUND)
         fl = tkn.GetNextToken();
         index = m_styleNames.Index(fl);
         if (index != wxNOT_FOUND)
+        {
             style |= m_styleValues[index];
             style |= m_styleValues[index];
+        }
         else
         else
-            wxLogError(_("Unknown style flag ") + fl);
+        {
+            ReportParamError
+            (
+                param,
+                wxString::Format("unknown style flag \"%s\"", fl)
+            );
+        }
     }
     return style;
 }
     }
     return style;
 }
@@ -1110,50 +1288,97 @@ wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour&
         if (clr.Ok())
             return clr;
 
         if (clr.Ok())
             return clr;
 
-        wxLogError(_("XRC resource: Incorrect colour specification '%s' for attribute '%s'."),
-                   v.c_str(), param.c_str());
+        ReportParamError
+        (
+            param,
+            wxString::Format("incorrect colour specification \"%s\"", v)
+        );
         return wxNullColour;
     }
 
     return clr;
 }
 
         return wxNullColour;
     }
 
     return clr;
 }
 
+namespace
+{
+
+// if 'param' has stock_id/stock_client, extracts them and returns true
+bool GetStockArtAttrs(const wxXmlNode *paramNode,
+                      const wxString& defaultArtClient,
+                      wxString& art_id, wxString& art_client)
+{
+    if ( paramNode )
+    {
+        art_id = paramNode->GetAttribute("stock_id", "");
+
+        if ( !art_id.empty() )
+        {
+            art_id = wxART_MAKE_ART_ID_FROM_STR(art_id);
 
 
+            art_client = paramNode->GetAttribute("stock_client", "");
+            if ( art_client.empty() )
+                art_client = defaultArtClient;
+            else
+                art_client = wxART_MAKE_CLIENT_ID_FROM_STR(art_client);
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+} // anonymous namespace
 
 wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
                                          const wxArtClient& defaultArtClient,
                                          wxSize size)
 {
 
 wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
                                          const wxArtClient& defaultArtClient,
                                          wxSize size)
 {
-    /* If the bitmap is specified as stock item, query wxArtProvider for it: */
-    wxXmlNode *bmpNode = GetParamNode(param);
-    if ( bmpNode )
+    // it used to be possible to pass an empty string here to indicate that the
+    // bitmap name should be read from this node itself but this is not
+    // supported any more because GetBitmap(m_node) can be used directly
+    // instead
+    wxASSERT_MSG( !param.empty(), "bitmap parameter name can't be empty" );
+
+    const wxXmlNode* const node = GetParamNode(param);
+
+    if ( !node )
     {
     {
-        wxString sid = bmpNode->GetAttribute(wxT("stock_id"), wxEmptyString);
-        if ( !sid.empty() )
-        {
-            wxString scl = bmpNode->GetAttribute(wxT("stock_client"), wxEmptyString);
-            if (scl.empty())
-                scl = defaultArtClient;
-            else
-                scl = wxART_MAKE_CLIENT_ID_FROM_STR(scl);
+        // this is not an error as bitmap parameter could be optional
+        return wxNullBitmap;
+    }
 
 
-            wxBitmap stockArt =
-                wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(sid),
-                                         scl, size);
-            if ( stockArt.Ok() )
-                return stockArt;
-        }
+    return GetBitmap(node, defaultArtClient, size);
+}
+
+wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node,
+                                         const wxArtClient& defaultArtClient,
+                                         wxSize size)
+{
+    wxCHECK_MSG( node, wxNullBitmap, "bitmap node can't be NULL" );
+
+    /* If the bitmap is specified as stock item, query wxArtProvider for it: */
+    wxString art_id, art_client;
+    if ( GetStockArtAttrs(node, defaultArtClient,
+                          art_id, art_client) )
+    {
+        wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size));
+        if ( stockArt.Ok() )
+            return stockArt;
     }
 
     /* ...or load the bitmap from file: */
     }
 
     /* ...or load the bitmap from file: */
-    wxString name = GetParamValue(param);
+    wxString name = GetParamValue(node);
     if (name.empty()) return wxNullBitmap;
 #if wxUSE_FILESYSTEM
     wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
     if (fsfile == NULL)
     {
     if (name.empty()) return wxNullBitmap;
 #if wxUSE_FILESYSTEM
     wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
     if (fsfile == NULL)
     {
-        wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
-                   name.c_str());
+        ReportParamError
+        (
+            node->GetName(),
+            wxString::Format("cannot open bitmap resource \"%s\"", name)
+        );
         return wxNullBitmap;
     }
     wxImage img(*(fsfile->GetStream()));
         return wxNullBitmap;
     }
     wxImage img(*(fsfile->GetStream()));
@@ -1164,8 +1389,11 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
 
     if (!img.Ok())
     {
 
     if (!img.Ok())
     {
-        wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
-                   name.c_str());
+        ReportParamError
+        (
+            node->GetName(),
+            wxString::Format("cannot create bitmap from \"%s\"", name)
+        );
         return wxNullBitmap;
     }
     if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
         return wxNullBitmap;
     }
     if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
@@ -1176,13 +1404,118 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
 wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
                                      const wxArtClient& defaultArtClient,
                                      wxSize size)
 wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
                                      const wxArtClient& defaultArtClient,
                                      wxSize size)
+{
+    // see comment in GetBitmap(wxString) overload
+    wxASSERT_MSG( !param.empty(), "icon parameter name can't be empty" );
+
+    const wxXmlNode* const node = GetParamNode(param);
+
+    if ( !node )
+    {
+        // this is not an error as icon parameter could be optional
+        return wxIcon();
+    }
+
+    return GetIcon(node, defaultArtClient, size);
+}
+
+wxIcon wxXmlResourceHandler::GetIcon(const wxXmlNode* node,
+                                     const wxArtClient& defaultArtClient,
+                                     wxSize size)
 {
     wxIcon icon;
 {
     wxIcon icon;
-    icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size));
+    icon.CopyFromBitmap(GetBitmap(node, defaultArtClient, size));
     return icon;
 }
 
 
     return icon;
 }
 
 
+wxIconBundle wxXmlResourceHandler::GetIconBundle(const wxString& param,
+                                                 const wxArtClient& defaultArtClient)
+{
+    wxString art_id, art_client;
+    if ( GetStockArtAttrs(GetParamNode(param), defaultArtClient,
+                          art_id, art_client) )
+    {
+        wxIconBundle stockArt(wxArtProvider::GetIconBundle(art_id, art_client));
+        if ( stockArt.IsOk() )
+            return stockArt;
+    }
+
+    const wxString name = GetParamValue(param);
+    if ( name.empty() )
+        return wxNullIconBundle;
+
+#if wxUSE_FILESYSTEM
+    wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
+    if ( fsfile == NULL )
+    {
+        ReportParamError
+        (
+            param,
+            wxString::Format("cannot open icon resource \"%s\"", name)
+        );
+        return wxNullIconBundle;
+    }
+
+    wxIconBundle bundle(*(fsfile->GetStream()));
+    delete fsfile;
+#else
+    wxIconBundle bundle(name);
+#endif
+
+    if ( !bundle.IsOk() )
+    {
+        ReportParamError
+        (
+            param,
+            wxString::Format("cannot create icon from \"%s\"", name)
+        );
+        return wxNullIconBundle;
+    }
+
+    return bundle;
+}
+
+
+wxImageList *wxXmlResourceHandler::GetImageList(const wxString& param)
+{
+    wxXmlNode * const imagelist_node = GetParamNode(param);
+    if ( !imagelist_node )
+        return NULL;
+
+    wxXmlNode * const oldnode = m_node;
+    m_node = imagelist_node;
+
+    // size
+    wxSize size = GetSize();
+    size.SetDefaults(wxSize(wxSystemSettings::GetMetric(wxSYS_ICON_X),
+                            wxSystemSettings::GetMetric(wxSYS_ICON_Y)));
+
+    // mask: true by default
+    bool mask = HasParam(wxT("mask")) ? GetBool(wxT("mask"), true) : true;
+
+    // now we have everything we need to create the image list
+    wxImageList *imagelist = new wxImageList(size.x, size.y, mask);
+
+    // add images
+    wxString parambitmap = wxT("bitmap");
+    if ( HasParam(parambitmap) )
+    {
+        wxXmlNode *n = m_node->GetChildren();
+        while (n)
+        {
+            if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == parambitmap)
+            {
+                // add icon instead of bitmap to keep the bitmap mask
+                imagelist->Add(GetIcon(n));
+            }
+            n = n->GetNext();
+        }
+    }
+
+    m_node = oldnode;
+    return imagelist;
+}
 
 wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
 {
 
 wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
 {
@@ -1193,14 +1526,20 @@ wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
     while (n)
     {
         if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
     while (n)
     {
         if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
+        {
+            // TODO: check that there are no other properties/parameters with
+            //       the same name and log an error if there are (can't do this
+            //       right now as I'm not sure if it's not going to break code
+            //       using this function in unintentional way (i.e. for
+            //       accessing other things than properties), for example
+            //       wxBitmapComboBoxXmlHandler almost surely does
             return n;
             return n;
+        }
         n = n->GetNext();
     }
     return NULL;
 }
 
         n = n->GetNext();
     }
     return NULL;
 }
 
-
-
 bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
 {
     return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
 bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
 {
     return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
@@ -1208,9 +1547,9 @@ bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
 
 
 
 
 
 
-wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
+wxString wxXmlResourceHandler::GetNodeContent(const wxXmlNode *node)
 {
 {
-    wxXmlNode *n = node;
+    const wxXmlNode *n = node;
     if (n == NULL) return wxEmptyString;
     n = n->GetChildren();
 
     if (n == NULL) return wxEmptyString;
     n = n->GetChildren();
 
@@ -1234,6 +1573,10 @@ wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
         return GetNodeContent(GetParamNode(param));
 }
 
         return GetNodeContent(GetParamNode(param));
 }
 
+wxString wxXmlResourceHandler::GetParamValue(const wxXmlNode* node)
+{
+    return GetNodeContent(node);
+}
 
 
 wxSize wxXmlResourceHandler::GetSize(const wxString& param,
 
 
 wxSize wxXmlResourceHandler::GetSize(const wxString& param,
@@ -1250,7 +1593,11 @@ wxSize wxXmlResourceHandler::GetSize(const wxString& param,
     if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
         !s.AfterLast(wxT(',')).ToLong(&sy))
     {
     if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
         !s.AfterLast(wxT(',')).ToLong(&sy))
     {
-        wxLogError(_("Cannot parse coordinates from '%s'."), s.c_str());
+        ReportParamError
+        (
+            param,
+            wxString::Format("cannot parse coordinates value \"%s\"", s)
+        );
         return wxDefaultSize;
     }
 
         return wxDefaultSize;
     }
 
@@ -1266,7 +1613,11 @@ wxSize wxXmlResourceHandler::GetSize(const wxString& param,
         }
         else
         {
         }
         else
         {
-            wxLogError(_("Cannot convert dialog units: dialog unknown."));
+            ReportParamError
+            (
+                param,
+                "cannot convert dialog units: dialog unknown"
+            );
             return wxDefaultSize;
         }
     }
             return wxDefaultSize;
         }
     }
@@ -1298,7 +1649,11 @@ wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
 
     if (!s.ToLong(&sx))
     {
 
     if (!s.ToLong(&sx))
     {
-        wxLogError(_("Cannot parse dimension from '%s'."), s.c_str());
+        ReportParamError
+        (
+            param,
+            wxString::Format("cannot parse dimension value \"%s\"", s)
+        );
         return defaultv;
     }
 
         return defaultv;
     }
 
@@ -1314,7 +1669,11 @@ wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
         }
         else
         {
         }
         else
         {
-            wxLogError(_("Cannot convert dialog units: dialog unknown."));
+            ReportParamError
+            (
+                param,
+                "cannot convert dialog units: dialog unknown"
+            );
             return defaultv;
         }
     }
             return defaultv;
         }
     }
@@ -1335,7 +1694,6 @@ static wxFont GetSystemFont(const wxString& name)
         SYSFNT(wxSYS_ANSI_VAR_FONT)
         SYSFNT(wxSYS_SYSTEM_FONT)
         SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
         SYSFNT(wxSYS_ANSI_VAR_FONT)
         SYSFNT(wxSYS_SYSTEM_FONT)
         SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
-        SYSFNT(wxSYS_DEFAULT_PALETTE)
         SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
         SYSFNT(wxSYS_DEFAULT_GUI_FONT)
         #undef SYSFNT
         SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
         SYSFNT(wxSYS_DEFAULT_GUI_FONT)
         #undef SYSFNT
@@ -1349,7 +1707,8 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param)
     wxXmlNode *font_node = GetParamNode(param);
     if (font_node == NULL)
     {
     wxXmlNode *font_node = GetParamNode(param);
     if (font_node == NULL)
     {
-        wxLogError(_("Cannot find font node '%s'."), param.c_str());
+        ReportError(
+            wxString::Format("cannot find font node \"%s\"", param));
         return wxNullFont;
     }
 
         return wxNullFont;
     }
 
@@ -1512,17 +1871,13 @@ void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
 
 void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
 {
 
 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);
         }
         {
             m_resource->CreateResFromNode(n, parent, NULL,
                                           this_hnd_only ? this : NULL);
         }
-        n = n->GetNext();
     }
 }
 
     }
 }
 
@@ -1544,12 +1899,63 @@ void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *
 }
 
 
 }
 
 
+//-----------------------------------------------------------------------------
+// errors reporting
+//-----------------------------------------------------------------------------
+
+void wxXmlResourceHandler::ReportError(const wxString& message)
+{
+    m_resource->ReportError(m_node, message);
+}
+
+void wxXmlResourceHandler::ReportError(wxXmlNode *context,
+                                       const wxString& message)
+{
+    m_resource->ReportError(context ? context : m_node, message);
+}
+
+void wxXmlResourceHandler::ReportParamError(const wxString& param,
+                                            const wxString& message)
+{
+    m_resource->ReportError(GetParamNode(param), message);
+}
 
 
+void wxXmlResource::ReportError(wxXmlNode *context, const wxString& message)
+{
+    if ( !context )
+    {
+        DoReportError("", NULL, message);
+        return;
+    }
 
 
+    // We need to find out the file that 'context' is part of. Performance of
+    // this code is not critical, so we simply find the root XML node and
+    // compare it with all loaded XRC files.
+    const wxString filename = GetFileNameFromNode(context, Data());
 
 
+    DoReportError(filename, context, message);
+}
 
 
+void wxXmlResource::DoReportError(const wxString& xrcFile, wxXmlNode *position,
+                                  const wxString& message)
+{
+    const int line = position ? position->GetLineNumber() : -1;
 
 
-// --------------- XRCID implementation -----------------------------
+    wxString loc;
+    if ( !xrcFile.empty() )
+        loc = xrcFile + ':';
+    if ( line != -1 )
+        loc += wxString::Format("%d:", line);
+    if ( !loc.empty() )
+        loc += ' ';
+
+    wxLogError("XRC error: %s%s", loc, message);
+}
+
+
+//-----------------------------------------------------------------------------
+// XRCID implementation
+//-----------------------------------------------------------------------------
 
 #define XRCID_TABLE_SIZE     1024
 
 
 #define XRCID_TABLE_SIZE     1024
 
@@ -1625,6 +2031,20 @@ int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found)
     return XRCID_Lookup(str_id, value_if_not_found);
 }
 
     return XRCID_Lookup(str_id, value_if_not_found);
 }
 
+/* static */
+wxString wxXmlResource::FindXRCIDById(int numId)
+{
+    for ( int i = 0; i < XRCID_TABLE_SIZE; i++ )
+    {
+        for ( XRCID_record *rec = XRCID_Records[i]; rec; rec = rec->next )
+        {
+            if ( rec->id == numId )
+                return wxString(rec->key);
+        }
+    }
+
+    return wxString();
+}
 
 static void CleanXRCID_Record(XRCID_record *rec)
 {
 
 static void CleanXRCID_Record(XRCID_record *rec)
 {
@@ -1778,7 +2198,9 @@ static void AddStdXRCID_Records()
 
 
 
 
 
 
-// --------------- module and globals -----------------------------
+//-----------------------------------------------------------------------------
+// module and globals
+//-----------------------------------------------------------------------------
 
 // normally we would do the cleanup from wxXmlResourceModule::OnExit() but it
 // can happen that some XRC records have been created because of the use of
 
 // normally we would do the cleanup from wxXmlResourceModule::OnExit() but it
 // can happen that some XRC records have been created because of the use of