X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/eb2d0d232c7d9ba22c5e82d5b7413b2d647e6c9c..43c5b6e808f083617eb42cb48e77366844f8fb5c:/src/xrc/xmlres.cpp diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp index 0d26338fc0..075489d9e7 100644 --- a/src/xrc/xmlres.cpp +++ b/src/xrc/xmlres.cpp @@ -44,9 +44,10 @@ #include "wx/fontenum.h" #include "wx/fontmap.h" #include "wx/artprov.h" - +#include "wx/dir.h" #include "wx/xml/xml.h" + class wxXmlResourceDataRecord { public: @@ -64,11 +65,27 @@ public: #endif }; -class wxXmlResourceDataRecords : public wxVector +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")); +} + +} // anonymous namespace + wxXmlResource *wxXmlResource::ms_instance = NULL; @@ -107,6 +124,11 @@ wxXmlResource::~wxXmlResource() { ClearHandlers(); + for ( wxXmlResourceDataRecords::iterator i = m_data->begin(); + i != m_data->end(); ++i ) + { + delete *i; + } delete m_data; } @@ -156,11 +178,34 @@ bool wxXmlResource::IsArchive(const wxString& filename) #endif // wxUSE_FILESYSTEM -bool wxXmlResource::Load(const wxString& filemask) +bool wxXmlResource::LoadFile(const wxFileName& file) { - wxString fnd; - bool iswild = wxIsWild(filemask); - bool rt = true; +#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; @@ -170,35 +215,35 @@ bool wxXmlResource::Load(const wxString& filemask) # define wxXmlFindFirst wxFindFirstFile(filemask, wxFILE) # define wxXmlFindNext wxFindNextFile() #endif - if (iswild) - fnd = wxXmlFindFirst; - else - fnd = filemask; - while (!fnd.empty()) + wxString fnd = wxXmlFindFirst; + if ( fnd.empty() ) { - fnd = ConvertFileNameToURL(fnd); + wxLogError(_("Cannot load resources from '%s'."), filemask); + return false; + } + while (!fnd.empty()) + { #if wxUSE_FILESYSTEM if ( IsArchive(fnd) ) { - rt = rt && Load(fnd + wxT("#zip:*.xrc")); + if ( !Load(fnd + wxT("#zip:*.xrc")) ) + return false; } else // a single resource URL #endif // wxUSE_FILESYSTEM { - wxXmlResourceDataRecord drec; - drec.File = fnd; + wxXmlResourceDataRecord *drec = new wxXmlResourceDataRecord; + drec->File = fnd; Data().push_back(drec); } - if (iswild) - fnd = wxXmlFindNext; - else - fnd = wxEmptyString; + fnd = wxXmlFindNext; } # undef wxXmlFindFirst # undef wxXmlFindNext - return rt && UpdateResources(); + + return UpdateResources(); } bool wxXmlResource::Unload(const wxString& filename) @@ -220,15 +265,16 @@ bool wxXmlResource::Unload(const wxString& filename) #if wxUSE_FILESYSTEM if ( isArchive ) { - if ( i->File.StartsWith(fnd) ) + if ( (*i)->File.StartsWith(fnd) ) unloaded = true; // don't break from the loop, we can have other matching files } else // a single resource URL #endif // wxUSE_FILESYSTEM { - if ( i->File == fnd ) + if ( (*i)->File == fnd ) { + delete *i; Data().erase(i); unloaded = true; @@ -361,7 +407,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); @@ -444,27 +490,29 @@ bool wxXmlResource::UpdateResources() for ( wxXmlResourceDataRecords::iterator i = Data().begin(); i != Data().end(); ++i ) { - modif = (i->Doc == NULL); + wxXmlResourceDataRecord* const rec = *i; + + modif = (rec->Doc == NULL); if (!modif && !(m_flags & wxXRC_NO_RELOADING)) { # if wxUSE_FILESYSTEM - file = fsys.OpenFile(i->File); + file = fsys.OpenFile(rec->File); # if wxUSE_DATETIME - modif = file && file->GetModificationTime() > i->Time; + modif = file && file->GetModificationTime() > rec->Time; # else // wxUSE_DATETIME modif = true; # endif // wxUSE_DATETIME if (!file) { - wxLogError(_("Cannot open file '%s'."), i->File.c_str()); + wxLogError(_("Cannot open file '%s'."), rec->File); rt = false; } wxDELETE(file); wxUnusedVar(file); # else // wxUSE_FILESYSTEM # if wxUSE_DATETIME - modif = wxDateTime(wxFileModificationTime(i->File)) > i->Time; + modif = wxDateTime(wxFileModificationTime(rec->File)) > rec->Time; # else // wxUSE_DATETIME modif = true; # endif // wxUSE_DATETIME @@ -473,42 +521,45 @@ bool wxXmlResource::UpdateResources() if (modif) { - wxLogTrace(_T("xrc"), - _T("opening file '%s'"), i->File.c_str()); + wxLogTrace(_T("xrc"), _T("opening file '%s'"), rec->File); wxInputStream *stream = NULL; # if wxUSE_FILESYSTEM - file = fsys.OpenFile(i->File); + file = fsys.OpenFile(rec->File); if (file) stream = file->GetStream(); # else - stream = new wxFileInputStream(i->File); + stream = new wxFileInputStream(rec->File); # endif if (stream) { - delete i->Doc; - i->Doc = new wxXmlDocument; + delete rec->Doc; + rec->Doc = new wxXmlDocument; } - if (!stream || !i->Doc->Load(*stream, encoding)) + if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding)) { wxLogError(_("Cannot load resources from file '%s'."), - i->File.c_str()); - wxDELETE(i->Doc); + rec->File); + wxDELETE(rec->Doc); rt = false; } - else if (i->Doc->GetRoot()->GetName() != wxT("resource")) + else if (rec->Doc->GetRoot()->GetName() != wxT("resource")) { - wxLogError(_("Invalid XRC resource '%s': doesn't have root node 'resource'."), i->File.c_str()); - wxDELETE(i->Doc); + ReportError + ( + rec->Doc->GetRoot(), + "invalid XRC resource, doesn't have root node " + ); + wxDELETE(rec->Doc); rt = false; } else { long version; int v1, v2, v3, v4; - wxString verstr = i->Doc->GetRoot()->GetAttribute( + wxString verstr = rec->Doc->GetRoot()->GetAttribute( wxT("version"), wxT("0.0.0.0")); if (wxSscanf(verstr.c_str(), wxT("%i.%i.%i.%i"), &v1, &v2, &v3, &v4) == 4) @@ -519,16 +570,16 @@ 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; } - ProcessPlatformProperty(i->Doc->GetRoot()); + ProcessPlatformProperty(rec->Doc->GetRoot()); #if wxUSE_DATETIME #if wxUSE_FILESYSTEM - i->Time = file->GetModificationTime(); + rec->Time = file->GetModificationTime(); #else // wxUSE_FILESYSTEM - i->Time = wxDateTime(wxFileModificationTime(i->File)); + rec->Time = wxDateTime(wxFileModificationTime(rec->File)); #endif // wxUSE_FILESYSTEM #endif // wxUSE_DATETIME } @@ -545,85 +596,121 @@ 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 ) { - if ( f->Doc == NULL || f->Doc->GetRoot() == NULL ) + wxXmlResourceDataRecord *const rec = *f; + wxXmlDocument * const doc = rec->Doc; + if ( !doc || !doc->GetRoot() ) continue; - wxXmlNode* found = DoFindResource(f->Doc->GetRoot(), - name, classname, recursive); + wxXmlNode * const + found = DoFindResource(doc->GetRoot(), name, classname, recursive); if ( found ) { -#if wxUSE_FILESYSTEM - m_curFileSystem.ChangePathTo(f->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; } @@ -698,8 +785,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; } @@ -727,9 +821,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; } @@ -801,8 +902,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 + ) + ); } } } @@ -876,9 +984,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; } @@ -890,22 +1006,21 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) wxXmlNode *parNode = GetParamNode(param); wxString str1(GetNodeContent(parNode)); wxString str2; - const wxChar *dt; - wxChar amp_char; + + // "\\" wasn't translated to "\" prior to 2.5.3.0: + const bool escapeBackslash = (m_resource->CompareVersion(2,5,3,0) >= 0); // VS: First version of XRC resources used $ instead of & (which is // illegal in XML), but later I realized that '_' fits this purpose // much better (because &File means "File with F underlined"). - if (m_resource->CompareVersion(2,3,0,1) < 0) - amp_char = wxT('$'); - else - amp_char = wxT('_'); + const wxChar amp_char = (m_resource->CompareVersion(2,3,0,1) < 0) + ? '$' : '_'; - for (dt = str1.c_str(); *dt; dt++) + for ( wxString::const_iterator dt = str1.begin(); dt != str1.end(); ++dt ) { // Remap amp_char to &, map double amp_char to amp_char (for things // like "&File..." -- this is illegal in XML, so we use "_File..."): - if (*dt == amp_char) + if ( *dt == amp_char ) { if ( *(++dt) == amp_char ) str2 << amp_char; @@ -913,8 +1028,9 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) str2 << wxT('&') << *dt; } // Remap \n to CR, \r to LF, \t to TAB, \\ to \: - else if (*dt == wxT('\\')) - switch (*(++dt)) + else if ( *dt == wxT('\\') ) + { + switch ( (*(++dt)).GetValue() ) { case wxT('n'): str2 << wxT('\n'); @@ -930,7 +1046,7 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) case wxT('\\') : // "\\" wasn't translated to "\" prior to 2.5.3.0: - if (m_resource->CompareVersion(2,5,3,0) >= 0) + if ( escapeBackslash ) { str2 << wxT('\\'); break; @@ -941,7 +1057,11 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) str2 << wxT('\\') << *dt; break; } - else str2 << *dt; + } + else + { + str2 << *dt; + } } if (m_resource->GetFlags() & wxXRC_USE_LOCALE) @@ -958,7 +1078,7 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) #else // The string is internally stored as UTF-8, we have to convert // it into system's default encoding so that it can be displayed: - return wxString(str2.mb_str(wxConvUTF8), wxConvLocal); + return wxString(str2.wc_str(wxConvUTF8), wxConvLocal); #endif } } @@ -986,6 +1106,7 @@ float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv) { wxString str = GetParamValue(param); +#if wxUSE_INTL // strings in XRC always use C locale but wxString::ToDouble() uses the // current one, so transform the string to it supposing that the only // difference between them is the decimal separator @@ -993,6 +1114,7 @@ float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv) // TODO: use wxString::ToCDouble() when we have it str.Replace(wxT("."), wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER)); +#endif // wxUSE_INTL double value; if (!str.ToDouble(&value)) @@ -1016,13 +1138,17 @@ wxString wxXmlResourceHandler::GetName() +bool wxXmlResourceHandler::GetBoolAttr(const wxString& attr, bool defaultv) +{ + wxString v; + return m_node->GetAttribute(attr, &v) ? v == '1' : defaultv; +} + bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv) { - wxString v = GetParamValue(param); - v.MakeLower(); - if (!v) return defaultv; + const wxString v = GetParamValue(param); - return (v == wxT("1")); + return v.empty() ? defaultv : (v == '1'); } @@ -1093,8 +1219,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; } @@ -1135,8 +1264,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())); @@ -1147,48 +1279,17 @@ 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); return wxBitmap(img); } -#if wxUSE_ANIMATIONCTRL -wxAnimation wxXmlResourceHandler::GetAnimation(const wxString& param) -{ - wxAnimation ani; - - /* load the animation from file: */ - wxString name = GetParamValue(param); - if (name.empty()) return wxNullAnimation; -#if wxUSE_FILESYSTEM - wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE); - if (fsfile == NULL) - { - wxLogError(_("XRC resource: Cannot create animation from '%s'."), - name.c_str()); - return wxNullAnimation; - } - ani.Load(*(fsfile->GetStream())); - delete fsfile; -#else - ani.LoadFile(name); -#endif - - if (!ani.IsOk()) - { - wxLogError(_("XRC resource: Cannot create animation from '%s'."), - name.c_str()); - return wxNullAnimation; - } - - return ani; -} -#endif // wxUSE_ANIMATIONCTRL - - wxIcon wxXmlResourceHandler::GetIcon(const wxString& param, const wxArtClient& defaultArtClient, @@ -1210,14 +1311,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; @@ -1267,7 +1374,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; } @@ -1283,7 +1394,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; } } @@ -1315,7 +1430,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; } @@ -1331,7 +1450,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; } } @@ -1352,7 +1475,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 @@ -1366,7 +1488,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; } @@ -1429,8 +1552,9 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) if (hasFacename) { wxString faces = GetParamValue(wxT("face")); - wxArrayString facenames(wxFontEnumerator::GetFacenames()); wxStringTokenizer tk(faces, wxT(",")); +#if wxUSE_FONTENUM + wxArrayString facenames(wxFontEnumerator::GetFacenames()); while (tk.HasMoreTokens()) { int index = facenames.Index(tk.GetNextToken(), false); @@ -1440,6 +1564,11 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) break; } } +#else // !wxUSE_FONTENUM + // just use the first face name if we can't check its availability: + if (tk.HasMoreTokens()) + facename = tk.GetNextToken(); +#endif // wxUSE_FONTENUM/!wxUSE_FONTENUM } // encoding @@ -1523,17 +1652,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(); } } @@ -1555,19 +1680,97 @@ 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 struct XRCID_record { - int id; + /* Hold the id so that once an id is allocated for a name, it + does not get created again by NewControlId at least + until we are done with it */ + wxWindowIDRef id; char *key; XRCID_record *next; }; @@ -1610,7 +1813,7 @@ static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE) } else { - (*rec_var)->id = wxNewId(); + (*rec_var)->id = wxWindowBase::NewControlId(); } } @@ -1633,12 +1836,27 @@ 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) { if (rec) { CleanXRCID_Record(rec->next); + free(rec->key); delete rec; } @@ -1682,6 +1900,7 @@ static void AddStdXRCID_Records() stdID(wxID_HELP_CONTEXT); stdID(wxID_CLOSE_ALL); stdID(wxID_PREFERENCES); + stdID(wxID_EDIT); stdID(wxID_CUT); stdID(wxID_COPY); stdID(wxID_PASTE); @@ -1758,6 +1977,24 @@ static void AddStdXRCID_Records() stdID(wxID_MAXIMIZE_FRAME); stdID(wxID_ICONIZE_FRAME); stdID(wxID_RESTORE_FRAME); + stdID(wxID_CDROM); + stdID(wxID_CONVERT); + stdID(wxID_EXECUTE); + stdID(wxID_FLOPPY); + stdID(wxID_HARDDISK); + stdID(wxID_BOTTOM); + stdID(wxID_FIRST); + stdID(wxID_LAST); + stdID(wxID_TOP); + stdID(wxID_INFO); + stdID(wxID_JUMP_TO); + stdID(wxID_NETWORK); + stdID(wxID_SELECT_COLOR); + stdID(wxID_SELECT_FONT); + stdID(wxID_SORT_ASCENDING); + stdID(wxID_SORT_DESCENDING); + stdID(wxID_SPELL_CHECK); + stdID(wxID_STRIKETHROUGH); #undef stdID } @@ -1766,7 +2003,20 @@ 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 +// XRCID() in event tables, which happens during static objects initialization, +// but then the application initialization failed and so the wx modules were +// neither initialized nor cleaned up -- this static object does the cleanup in +// this case +static struct wxXRCStaticCleanup +{ + ~wxXRCStaticCleanup() { CleanXRCID_Records(); } +} s_staticCleanup; class wxXmlResourceModule: public wxModule {