X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e5bb501b98ddb45a21569f9e9b0e8a8398fbd574..80f624ec0c99878e327bfd070d6a92adf48eac14:/src/xrc/xmlres.cpp?ds=inline diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp index efee9e17e5..d19bdec665 100644 --- a/src/xrc/xmlres.cpp +++ b/src/xrc/xmlres.cpp @@ -44,7 +44,8 @@ #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" @@ -70,6 +71,64 @@ class wxXmlResourceDataRecords : public wxVector // 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 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 and the referenced ); 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; @@ -162,8 +221,35 @@ bool wxXmlResource::IsArchive(const wxString& filename) #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) @@ -181,8 +267,6 @@ bool wxXmlResource::Load(const wxString& filemask) while (!fnd.empty()) { - fnd = ConvertFileNameToURL(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) { - 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); @@ -497,7 +581,7 @@ bool wxXmlResource::UpdateResources() 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); @@ -506,7 +590,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 " + ); wxDELETE(rec->Doc); rt = false; } @@ -525,7 +613,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; } @@ -551,93 +639,129 @@ bool wxXmlResource::UpdateResources() return rt; } - 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()) { - 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; + + wxString cls(node->GetAttribute(wxS("class"))); + // 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; - 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 ) + { 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; } } + } - return NULL; + return NULL; } 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(this)->UpdateResources(); - wxString dummy; 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; - wxXmlNode* found = DoFindResource(rec->Doc->GetRoot(), - name, classname, recursive); + wxXmlNode * const + found = DoFindResource(doc->GetRoot(), name, classname, recursive); if ( found ) { -#if wxUSE_FILESYSTEM - m_curFileSystem.ChangePathTo(rec->File); -#endif + if ( path ) + *path = rec->File; + return found; } } - wxLogError(_("XRC resource '%s' (class '%s') not found!"), - name.c_str(), classname.c_str()); return NULL; } -static void MergeNodes(wxXmlNode& dest, wxXmlNode& with) +static void MergeNodesOver(wxXmlNode& dest, wxXmlNode& overwriteWith, + const wxString& overwriteFilename) { // Merge attributes: - for ( wxXmlAttribute *attr = with.GetAttributes(); + for ( wxXmlAttribute *attr = overwriteWith.GetAttributes(); attr; attr = attr->GetNext() ) { wxXmlAttribute *dattr; @@ -656,7 +780,7 @@ static void MergeNodes(wxXmlNode& dest, wxXmlNode& with) } // 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; @@ -667,28 +791,32 @@ static void MergeNodes(wxXmlNode& dest, wxXmlNode& with) dnode->GetAttribute(wxT("name"), wxEmptyString) == name && dnode->GetType() == node->GetType() ) { - MergeNodes(*dnode, *node); + MergeNodesOver(*dnode, *node, overwriteFilename); 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 ) { - dest.AddChild(new wxXmlNode(*node)); + dest.AddChild(copyOfNode); } 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, @@ -705,15 +833,43 @@ 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; } - wxXmlNode copy(*refNode); - MergeNodes(copy, *node); + if ( !node->GetChildren() ) + { + // In the typical, simple case, 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(©, parent, instance); + return CreateResFromNode(refNode, parent, instance); + } + else + { + // In the more complicated (but rare) case, 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(©, parent, instance); + } } 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; } @@ -808,8 +971,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 + ) + ); } } } @@ -883,9 +1053,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; } @@ -1110,50 +1288,97 @@ 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; } 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) { - /* 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: */ - 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) { - 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())); @@ -1164,8 +1389,11 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param, 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); @@ -1176,13 +1404,118 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param, 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; - icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size)); + icon.CopyFromBitmap(GetBitmap(node, defaultArtClient, size)); 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) { @@ -1193,14 +1526,20 @@ wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& 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; + } n = n->GetNext(); } return NULL; } - - 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(); @@ -1234,6 +1573,10 @@ wxString wxXmlResourceHandler::GetParamValue(const wxString& param) return GetNodeContent(GetParamNode(param)); } +wxString wxXmlResourceHandler::GetParamValue(const wxXmlNode* node) +{ + return GetNodeContent(node); +} 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)) { - wxLogError(_("Cannot parse coordinates from '%s'."), s.c_str()); + ReportParamError + ( + param, + wxString::Format("cannot parse coordinates value \"%s\"", s) + ); return wxDefaultSize; } @@ -1266,7 +1613,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; } } @@ -1298,7 +1649,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; } @@ -1314,7 +1669,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; } } @@ -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_DEFAULT_PALETTE) 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) { - wxLogError(_("Cannot find font node '%s'."), param.c_str()); + ReportError( + wxString::Format("cannot find font node \"%s\"", param)); return wxNullFont; } @@ -1512,17 +1871,13 @@ void wxXmlResourceHandler::SetupWindow(wxWindow *wnd) 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); } - 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 @@ -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); } +/* 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) { @@ -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