]> git.saurik.com Git - wxWidgets.git/commitdiff
better XRC errors reporting: report location of the error and use unified formatting
authorVáclav Slavík <vslavik@fastmail.fm>
Sun, 15 Mar 2009 10:29:14 +0000 (10:29 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Sun, 15 Mar 2009 10:29:14 +0000 (10:29 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59556 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

18 files changed:
include/wx/xrc/xmlres.h
interface/wx/xrc/xmlres.h
src/xrc/xh_bmpcbox.cpp
src/xrc/xh_choicbk.cpp
src/xrc/xh_collpane.cpp
src/xrc/xh_listbk.cpp
src/xrc/xh_mdi.cpp
src/xrc/xh_menu.cpp
src/xrc/xh_notbk.cpp
src/xrc/xh_propdlg.cpp
src/xrc/xh_sizer.cpp
src/xrc/xh_split.cpp
src/xrc/xh_statbar.cpp
src/xrc/xh_toolb.cpp
src/xrc/xh_treebk.cpp
src/xrc/xh_wizrd.cpp
src/xrc/xmladv.cpp
src/xrc/xmlres.cpp

index c324aec9308e3d7e942c289a45d489e15b0b2fde..c130d915cfa051da0055244e4f353ba7a75f160f 100644 (file)
@@ -261,6 +261,13 @@ public:
         { return GetResourceNodeAndLocation(name, wxString(), true); }
 
 protected:
+    // reports input error at position 'context'
+    void ReportError(wxXmlNode *context, const wxString& message);
+
+    // override this in derived class to customize errors reporting
+    virtual void DoReportError(const wxString& xrcFile, wxXmlNode *position,
+                               const wxString& message);
+
     // Scans the resources list for unloaded files and loads them. Also reloads
     // files that have been modified since last loading.
     bool UpdateResources();
@@ -529,6 +536,13 @@ protected:
 #if wxUSE_FILESYSTEM
     wxFileSystem& GetCurFileSystem() { return m_resource->GetCurFileSystem(); }
 #endif
+
+    // reports input error at position 'context'
+    void ReportError(wxXmlNode *context, const wxString& message);
+    // reports input error at m_node
+    void ReportError(const wxString& message);
+    // reports input error when parsing parameter with given name
+    void ReportParamError(const wxString& param, const wxString& message);
 };
 
 
index 590b51ac300850c4daa47a0b76f3dfe1a59ee4a6..5bd3bce792769d0ad64b2a74e97eb64224061488 100644 (file)
@@ -334,6 +334,60 @@ public:
         hasn't been found in the list of loaded resources.
     */
     bool Unload(const wxString& filename);
+
+protected:
+    /**
+        Reports error in XRC resources to the user.
+
+        Any errors in XRC input files should be reported using this method
+        (or its wxXmlResourceHandler::ReportError() equivalent). Unlike
+        wxLogError(), this method presents the error to the user in a more
+        usable form. In particular, the output is compiler-like and contains
+        information about the exact location of the error.
+
+        @param context XML node the error occurred in or relates to. This can
+                       be @NULL, but should be the most specific node possible,
+                       as its line number is what is reported to the user.
+        @param message Text of the error message. This string should always
+                       be in English (i.e. not wrapped in _()). It shouldn't
+                       be a sentence -- it should start with lower-case letter
+                       and shouldn't have a trailing period or exclamation
+                       point.
+
+        @since 2.9.0
+
+        @see wxXmlResourceHandler::ReportError(), DoReportError()
+     */
+    void ReportError(wxXmlNode *context, const wxString& message);
+
+    /**
+        Implementation of XRC resources errors reporting.
+
+        This method is called by ReportError() and shouldn't be called
+        directly; use ReportError() or wxXmlResourceHandler::ReportError()
+        to log errors.
+
+        Default implementation uses wxLogError().
+
+        @param xrcFile  File the error occurred in or empty string if it
+                        couldn't be determined.
+        @param position XML node where the error occurred or @NULL if it
+                        couldn't be determined.
+        @param message  Text of the error message. See ReportError()
+                        documentation for details of the string's format.
+
+        @note
+        You may override this method in a derived class to customize errors
+        reporting. If you do so, you'll need to either use the derived class
+        in all your code or call wxXmlResource::Set() to change the global
+        wxXmlResource instance to your class.
+
+        @since 2.9.0
+
+        @see ReportError()
+    */
+    virtual void DoReportError(const wxString& xrcFile, wxXmlNode *position,
+                               const wxString& message);
 };
 
 
@@ -544,5 +598,32 @@ protected:
         Sets common window options.
     */
     void SetupWindow(wxWindow* wnd);
+
+    /**
+        Reports error in XRC resources to the user.
+
+        See wxXmlResource::ReportError() for more information.
+
+        @since 2.9.0
+     */
+    void ReportError(wxXmlNode *context, const wxString& message);
+
+    /**
+        Like ReportError(wxXmlNode*, const wxString&), but uses the node
+        of currently processed object (m_node) as the context.
+
+        @since 2.9.0
+     */
+    void ReportError(const wxString& message);
+
+    /**
+        Like ReportError(wxXmlNode*, const wxString&), but uses the node
+        of parameter @a param of the currently processed object as the context.
+        This is convenience function for reporting errors in particular
+        parameters.
+
+        @since 2.9.0
+     */
+    void ReportParamError(const wxString& param, const wxString& message);
 };
 
index 464f75b79fad172001882c7b04e5a9502cf84c35..43936df9dd8e66eb3dae870e46d1e32041fe1b0a 100644 (file)
@@ -44,8 +44,7 @@ wxObject *wxBitmapComboBoxXmlHandler::DoCreateResource()
     {
         if ( !m_combobox )
         {
-            wxLogError(_("XRC syntex error: ownerdrawnitem only allowed within "
-                         " a bitmapcombobox!"));
+            ReportError("ownerdrawnitem only allowed within a wxBitmapComboBox");
             return NULL;
         }
 
index 5b8aff619e41431d1c2a4ecc27b5a66048b1d12c..4b8390db17befba57f00f344f3b39015504a8989 100644 (file)
@@ -86,12 +86,14 @@ wxObject *wxChoicebookXmlHandler::DoCreateResource()
                 }
             }
             else
-                wxLogError(wxT("Error in resource."));
+            {
+                ReportError(n, "choicebookpage child must be a window");
+            }
             return wnd;
         }
         else
         {
-            wxLogError(wxT("Error in resource: no control within choicebook's <page> tag."));
+            ReportError("choicebookpage must have a window child");
             return NULL;
         }
     }
index bad9bcd9df42ae1213ea6e3f6c1cea2d6aa3e673..93ab13c3973e9dd4fec13fcd76f463109cbe3955 100644 (file)
@@ -54,7 +54,7 @@ wxObject *wxCollapsiblePaneXmlHandler::DoCreateResource()
         }
         else
         {
-            wxLogError(wxT("Error in resource: no control within collapsible pane's <panewindow> tag."));
+            ReportError("no control within panewindow");
             return NULL;
         }
     }
@@ -65,7 +65,7 @@ wxObject *wxCollapsiblePaneXmlHandler::DoCreateResource()
         wxString label = GetParamValue(wxT("label"));
         if (label.empty())
         {
-            wxLogError(wxT("Error in resource: empty label for wxCollapsiblePane"));
+            ReportParamError("label", "label cannot be empty");
             return NULL;
         }
 
index 36138404de0bcdbc162fc734df76c947506df083..470be509bac8231e0426b74327f137672774b914 100644 (file)
@@ -86,12 +86,14 @@ wxObject *wxListbookXmlHandler::DoCreateResource()
                 }
             }
             else
-                wxLogError(wxT("Error in resource."));
+            {
+                ReportError(n, "listbookpage child must be a window");
+            }
             return wnd;
         }
         else
         {
-            wxLogError(wxT("Error in resource: no control within listbook's <page> tag."));
+            ReportError("listbookpage must have a window child");
             return NULL;
         }
     }
index 95fa08e21e1758c13d1a90e4f4791fb0a1c8a5a5..f6fea842ddcb9ac6041a4a896fcc0b33d1814143 100644 (file)
@@ -88,7 +88,7 @@ wxWindow *wxMdiXmlHandler::CreateFrame()
 
         if ( !mdiParent )
         {
-            wxLogError(wxT("Parent of wxMDIChildFrame must be wxMDIParentFrame."));
+            ReportError("parent of wxMDIChildFrame must be wxMDIParentFrame");
             return NULL;
         }
 
index fe700cdd5c45b69eb3d1258ef563c92804bd8adb..f6cc1963f1c3d8187f8a8ccb6c8dc5b5ed776dd8 100644 (file)
@@ -91,9 +91,11 @@ wxObject *wxMenuXmlHandler::DoCreateResource()
             {
                 if ( kind != wxITEM_NORMAL )
                 {
-                    wxLogWarning(_("XRC syntax error: a menu item can't have "
-                                   "both \"radio\" and \"checkable\" "
-                                   "properties, ignoring the former."));
+                    ReportParamError
+                    (
+                        "checkable",
+                        "menu item can't have both <radio> and <checkable> properties"
+                    );
                 }
 
                 kind = wxITEM_CHECK;
index 01a280ef26fc6b195b49563fbc4fcb4aa6984c39..2908984fbf77a81c265c2bcbc38536356d87f062 100644 (file)
@@ -89,12 +89,14 @@ wxObject *wxNotebookXmlHandler::DoCreateResource()
                 }
             }
             else
-                wxLogError(wxT("Error in resource."));
+            {
+                ReportError(n, "notebookpage child must be a window");
+            }
             return wnd;
         }
         else
         {
-            wxLogError(wxT("Error in resource: no control within notebook's <page> tag."));
+            ReportError("notebookpage must have a window child");
             return NULL;
         }
     }
index 96bd4e2a23e930e033d155c87509c9c2e55f1637..0dd4f168f86eb683294d72eb2bb0a73cad23d510 100644 (file)
@@ -89,12 +89,14 @@ wxObject *wxPropertySheetDialogXmlHandler::DoCreateResource()
                 }
             }
             else
-                wxLogError(wxT("Error in resource."));
+            {
+                ReportError(n, "propertysheetpage child must be a window");
+            }
             return wnd;
         }
         else
         {
-            wxLogError(wxT("Error in resource: no control within wxPropertySheetDialog's <page> tag."));
+            ReportError("propertysheetpage must have a window child");
             return NULL;
         }
     }
index fb21758c0b6a2393eaa4d18974ad10a8b4f4179b..060d3bbbcd8fbf5274a9083ef562472d3dc87cd8 100644 (file)
@@ -161,7 +161,7 @@ wxObject* wxSizerXmlHandler::Handle_sizeritem()
         else if (wnd)
             sitem->AssignWindow(wnd);
         else
-            wxLogError(wxT("Error in resource."));
+            ReportError(n, "unexpected item in sizer");
 
         // finally, set other wxSizerItem attributes
         SetSizerItemAttributes(sitem);
@@ -171,7 +171,7 @@ wxObject* wxSizerXmlHandler::Handle_sizeritem()
     }
     else /*n == NULL*/
     {
-        wxLogError(wxT("Error in resource: no window/sizer/spacer within sizeritem object."));
+        ReportError("no window/sizer/spacer within sizeritem object");
         return NULL;
     }
 }
@@ -181,8 +181,7 @@ wxObject* wxSizerXmlHandler::Handle_spacer()
 {
     if ( !m_parentSizer )
     {
-        wxLogError(_("XRC syntax error: \"spacer\" only allowed inside a "
-                     "sizer"));
+        ReportError("spacer only allowed inside a sizer");
         return NULL;
     }
 
@@ -205,7 +204,7 @@ wxObject* wxSizerXmlHandler::Handle_sizer()
             (!parentNode || parentNode->GetType() != wxXML_ELEMENT_NODE ||
              !m_parentAsWindow) )
     {
-        wxLogError(_("XRC syntax error: sizer must have a window parent."));
+        ReportError("sizer must have a window parent");
         return NULL;
     }
 
@@ -232,7 +231,7 @@ wxObject* wxSizerXmlHandler::Handle_sizer()
 
     if ( !sizer )
     {
-        wxLogError(_T("Failed to create size of class \"%s\""), m_class.c_str());
+        ReportError(wxString::Format("unknown sizer class \"%s\"", m_class));
         return NULL;
     }
 
@@ -348,7 +347,11 @@ void wxSizerXmlHandler::SetGrowables(wxFlexGridSizer* sizer,
     {
         if (!tkn.GetNextToken().ToULong(&l))
         {
-            wxLogError(wxT("growable[rows|cols] must be comma-separated list of row numbers"));
+            ReportParamError
+            (
+                param,
+                "value must be comma-separated list of row numbers"
+            );
             break;
         }
 
@@ -467,13 +470,13 @@ wxObject *wxStdDialogButtonSizerXmlHandler::DoCreateResource()
             if (button)
                 m_parentSizer->AddButton(button);
             else
-                wxLogError(wxT("Error in resource - expected button."));
+                ReportError(n, "expected wxButton");
 
             return item;
         }
         else /*n == NULL*/
         {
-            wxLogError(wxT("Error in resource: no button within wxStdDialogButtonSizer."));
+            ReportError("no button within wxStdDialogButtonSizer");
             return NULL;
         }
     }
index fd219118089c2eb66f37ec5e7bd899e62910b6d7..e14300f4f9679a14068a7e8b7425cc718b4148d4 100644 (file)
@@ -87,7 +87,7 @@ wxObject *wxSplitterWindowXmlHandler::DoCreateResource()
     }
 
     if (win1 == NULL)
-        wxLogError(wxT("wxSplitterWindow node must contain at least one window."));
+        ReportError("wxSplitterWindow node must contain at least one window");
 
     bool horizontal = (GetParamValue(wxT("orientation")) != wxT("vertical"));
     if (win1 && win2)
index fe14c250d795d4078167fbf72c3bf529a25fb96c..0df6782e19490274dabe8e2b89a49b7410b04a9e 100644 (file)
@@ -79,7 +79,17 @@ wxObject *wxStatusBarXmlHandler::DoCreateResource()
             else if (first == wxT("wxSB_RAISED"))
                 style[i] = wxSB_RAISED;
             else if (!first.empty())
-                wxLogError(wxT("Error in resource, unknown statusbar field style: ") + first);
+            {
+                ReportParamError
+                (
+                    "styles",
+                    wxString::Format
+                    (
+                        "unknown status bar field style \"%s\"",
+                        first
+                    )
+                );
+            }
 
             if(styles.Find(wxT(',')))
                 styles.Remove(0, styles.Find(wxT(',')) + 1);
index b6f518d4af4b320c08b0082b0c00543d83cea9c7..2d19946e33629aff22f7e99cfe29d7da3cab7045 100644 (file)
@@ -57,8 +57,7 @@ wxObject *wxToolBarXmlHandler::DoCreateResource()
     {
         if ( !m_toolbar )
         {
-            wxLogError(_("XRC syntax error: \"tool\" only allowed inside a "
-                         "toolbar"));
+            ReportError("tool only allowed inside a wxToolBar");
             return NULL;
         }
 
@@ -70,9 +69,11 @@ wxObject *wxToolBarXmlHandler::DoCreateResource()
         {
             if ( kind != wxITEM_NORMAL )
             {
-                wxLogWarning(_("XRC syntax error: tool can't have both "
-                               "\"radio\" and \"toggle\" properties, "
-                               "ignoring the former."));
+                ReportParamError
+                (
+                    "toggle",
+                    "tool can't have both <radio> and <toggle> properties"
+                );
             }
 
             kind = wxITEM_CHECK;
@@ -85,9 +86,11 @@ wxObject *wxToolBarXmlHandler::DoCreateResource()
         {
             if ( kind != wxITEM_NORMAL )
             {
-                wxLogWarning(_("XRC syntax error: drop-down tool can't have "
-                               "neither \"radio\" nor \"toggle\" properties, "
-                               "ignoring them."));
+                ReportParamError
+                (
+                    "dropdown",
+                    "drop-down tool can't have neither <radio> nor <toggle> properties"
+                );
             }
 
             kind = wxITEM_DROPDOWN;
@@ -102,14 +105,20 @@ wxObject *wxToolBarXmlHandler::DoCreateResource()
                 menu = wxDynamicCast(res, wxMenu);
                 if ( !menu )
                 {
-                    wxLogError(_("XRC syntax error: invalid drop-down tool "
-                                 "contents (expected a menu)."));
+                    ReportError
+                    (
+                        nodeMenu,
+                        "drop-down tool contents can only be a wxMenu"
+                    );
                 }
 
                 if ( nodeMenu->GetNext() )
                 {
-                    wxLogWarning(_("XRC syntax error: unexpected extra "
-                                   "contents under drop-down tool."));
+                    ReportError
+                    (
+                        nodeMenu->GetNext(),
+                        "unexpected extra contents under drop-down tool"
+                    );
                 }
             }
         }
@@ -139,8 +148,7 @@ wxObject *wxToolBarXmlHandler::DoCreateResource()
     {
         if ( !m_toolbar )
         {
-            wxLogError(_("XRC syntax error: \"separator\" only allowed inside a "
-                         "toolbar"));
+            ReportError("separator only allowed inside wxToolBar");
             return NULL;
         }
         m_toolbar->AddSeparator();
index d3d427dfba7f35fed7cfa7197b1b01177c74ca15..cd199b7bb68c0863f325172f17256a1ac97abeda 100644 (file)
@@ -95,7 +95,9 @@ wxObject *wxTreebookXmlHandler::DoCreateResource()
         wnd = wxDynamicCast(item, wxWindow);
 
         if (wnd == NULL && item != NULL)
-            wxLogError(wxT("Error in resource: control within treebook's <page> tag is not a window."));
+        {
+            ReportError(n, "treebookpage child must be a window");
+        }
     }
 
     size_t depth = GetLong( wxT("depth") );
@@ -134,7 +136,10 @@ wxObject *wxTreebookXmlHandler::DoCreateResource()
 
     }
     else
-        wxLogError(wxT("Error in resource. wxTreebookPage has an invalid depth."));
+    {
+        ReportParamError("depth", "invalid depth");
+    }
+
     return wnd;
 }
 
index 7888b50e0caedcd63ca5e137a6981a1ebdddff3a..97dc42b94dd1b58728677b63c2f6009f5b69babb 100644 (file)
@@ -75,7 +75,7 @@ wxObject *wxWizardXmlHandler::DoCreateResource()
         {
             if ( !m_instance )
             {
-                wxLogError(wxT("wxWizardPage is abstract class, must be subclassed"));
+                ReportError("wxWizardPage is abstract class and must be subclassed");
                 return NULL;
             }
 
index ad3c96aa9315d22659d03b0866378f2111477d13..5087147e2fefed94c0c7ce09775ef97ac71f0ca5 100644 (file)
@@ -60,8 +60,11 @@ wxAnimation wxXmlResourceHandler::GetAnimation(const wxString& param)
 
     if ( !ani.IsOk() )
     {
-        wxLogError(_("XRC resource: Cannot create animation from '%s'."),
-                   name.c_str());
+        ReportParamError
+        (
+            param,
+            wxString::Format("cannot create animation from \"%s\"", name)
+        );
         return wxNullAnimation;
     }
 
index 6e7e3b9611e65e731ff6751625cc01ffe370113a..fc2fa3d3ce022d5fb52372a6f6e8314ba18abe0e 100644 (file)
@@ -403,7 +403,7 @@ bool wxXmlResource::AttachUnknownControl(const wxString& name,
     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);
@@ -543,7 +543,11 @@ bool wxXmlResource::UpdateResources()
             }
             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;
             }
@@ -562,7 +566,7 @@ bool wxXmlResource::UpdateResources()
                     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;
                 }
 
@@ -651,8 +655,15 @@ wxXmlNode *wxXmlResource::FindResource(const wxString& name,
 
     if ( !node )
     {
-        wxLogError(_("XRC resource '%s' (class '%s') not found!"),
-                   name, classname);
+        ReportError
+        (
+            NULL,
+            wxString::Format
+            (
+                "XRC resource \"%s\" (class \"%s\") not found",
+                name, classname
+            )
+        );
     }
 #if wxUSE_FILESYSTEM
     else // node was found
@@ -770,8 +781,15 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
 
         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;
         }
 
@@ -799,9 +817,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;
 }
 
@@ -873,8 +898,15 @@ wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent
             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
+                    )
+                );
             }
         }
     }
@@ -948,9 +980,17 @@ int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
         fl = tkn.GetNextToken();
         index = m_styleNames.Index(fl);
         if (index != wxNOT_FOUND)
+        {
             style |= m_styleValues[index];
+        }
         else
-            wxLogError(_("Unknown style flag ") + fl);
+        {
+            ReportParamError
+            (
+                param,
+                wxString::Format("unknown style flag \"%s\"", fl)
+            );
+        }
     }
     return style;
 }
@@ -1175,8 +1215,11 @@ wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour&
         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;
     }
 
@@ -1217,8 +1260,11 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
     wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
     if (fsfile == NULL)
     {
-        wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
-                   name.c_str());
+        ReportParamError
+        (
+            param,
+            wxString::Format("cannot open bitmap resource \"%s\"", name)
+        );
         return wxNullBitmap;
     }
     wxImage img(*(fsfile->GetStream()));
@@ -1229,8 +1275,11 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
 
     if (!img.Ok())
     {
-        wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
-                   name.c_str());
+        ReportParamError
+        (
+            param,
+            wxString::Format("cannot create bitmap from \"%s\"", name)
+        );
         return wxNullBitmap;
     }
     if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
@@ -1321,7 +1370,11 @@ wxSize wxXmlResourceHandler::GetSize(const wxString& param,
     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;
     }
 
@@ -1337,7 +1390,11 @@ wxSize wxXmlResourceHandler::GetSize(const wxString& param,
         }
         else
         {
-            wxLogError(_("Cannot convert dialog units: dialog unknown."));
+            ReportParamError
+            (
+                param,
+                "cannot convert dialog units: dialog unknown"
+            );
             return wxDefaultSize;
         }
     }
@@ -1369,7 +1426,11 @@ wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
 
     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;
     }
 
@@ -1385,7 +1446,11 @@ wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
         }
         else
         {
-            wxLogError(_("Cannot convert dialog units: dialog unknown."));
+            ReportParamError
+            (
+                param,
+                "cannot convert dialog units: dialog unknown"
+            );
             return defaultv;
         }
     }
@@ -1419,7 +1484,8 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param)
     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;
     }
 
@@ -1610,12 +1676,87 @@ 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);
+}
+
+namespace
+{
+
+wxString
+GetFileNameFromNode(wxXmlNode *node, const wxXmlResourceDataRecords& files)
+{
+    wxXmlNode *root = node;
+    while ( root->GetParent() )
+        root = root->GetParent();
+
+    for ( wxXmlResourceDataRecords::const_iterator i = files.begin();
+          i != files.end(); ++i )
+    {
+        if ( (*i)->Doc->GetRoot() == root )
+        {
+            return (*i)->File;
+        }
+    }
+
+    return wxEmptyString; // not found
+}
+
+} // anonymous namespace
+
+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;
+
+    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 -----------------------------
+//-----------------------------------------------------------------------------
+// XRCID implementation
+//-----------------------------------------------------------------------------
 
 #define XRCID_TABLE_SIZE     1024
 
@@ -1858,7 +1999,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