X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9a83f860948059b0273b5cc6d9e43fadad3ebfca..f363cee882672e147340240cf0bb194a68e37833:/src/xrc/xmlres.cpp diff --git a/src/xrc/xmlres.cpp b/src/xrc/xmlres.cpp index 82c3f10a89..862eabdbab 100644 --- a/src/xrc/xmlres.cpp +++ b/src/xrc/xmlres.cpp @@ -3,7 +3,6 @@ // Purpose: XRC resources // Author: Vaclav Slavik // Created: 2000/03/05 -// RCS-ID: $Id$ // Copyright: (c) 2000 Vaclav Slavik // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -47,16 +46,50 @@ #include "wx/imaglist.h" #include "wx/dir.h" #include "wx/xml/xml.h" +#include "wx/hashset.h" +#include "wx/scopedptr.h" +namespace +{ + +// Helper function to get modification time of either a wxFileSystem URI or +// just a normal file name, depending on the build. +#if wxUSE_DATETIME + +wxDateTime GetXRCFileModTime(const wxString& filename) +{ +#if wxUSE_FILESYSTEM + wxFileSystem fsys; + wxScopedPtr file(fsys.OpenFile(filename)); + + return file ? file->GetModificationTime() : wxDateTime(); +#else // wxUSE_FILESYSTEM + return wxDateTime(wxFileModificationTime(filename)); +#endif // wxUSE_FILESYSTEM +} + +#endif // wxUSE_DATETIME + +} // anonymous namespace + +// Assign the given value to the specified entry or add a new value with this +// name. +static void XRCID_Assign(const wxString& str_id, int value); class wxXmlResourceDataRecord { public: - wxXmlResourceDataRecord() : Doc(NULL) { + // Ctor takes ownership of the document pointer. + wxXmlResourceDataRecord(const wxString& File_, + wxXmlDocument *Doc_ + ) + : File(File_), Doc(Doc_) + { #if wxUSE_DATETIME - Time = wxDateTime::Now(); + Time = GetXRCFileModTime(File); #endif } + ~wxXmlResourceDataRecord() {delete Doc;} wxString File; @@ -64,6 +97,8 @@ public: #if wxUSE_DATETIME wxDateTime Time; #endif + + wxDECLARE_NO_COPY_CLASS(wxXmlResourceDataRecord); }; class wxXmlResourceDataRecords : public wxVector @@ -71,6 +106,66 @@ class wxXmlResourceDataRecords : public wxVector // this is a class so that it can be forward-declared }; +WX_DECLARE_HASH_SET_PTR(int, wxIntegerHash, wxIntegerEqual, wxHashSetInt); + +class wxIdRange // Holds data for a particular rangename +{ +protected: + wxIdRange(const wxXmlNode* node, + const wxString& rname, + const wxString& startno, + const wxString& rsize); + + // Note the existence of an item within the range + void NoteItem(const wxXmlNode* node, const wxString& item); + + // The manager is telling us that it's finished adding items + void Finalise(const wxXmlNode* node); + + wxString GetName() const { return m_name; } + bool IsFinalised() const { return m_finalised; } + + const wxString m_name; + int m_start; + int m_end; + unsigned int m_size; + bool m_item_end_found; + bool m_finalised; + wxHashSetInt m_indices; + + friend class wxIdRangeManager; +}; + +class wxIdRangeManager +{ +public: + ~wxIdRangeManager(); + // Gets the global resources object or creates one if none exists. + static wxIdRangeManager *Get(); + + // Sets the global resources object and returns a pointer to the previous + // one (may be NULL). + static wxIdRangeManager *Set(wxIdRangeManager *res); + + // Create a new IDrange from this node + void AddRange(const wxXmlNode* node); + // Tell the IdRange that this item exists, and should be pre-allocated an ID + void NotifyRangeOfItem(const wxXmlNode* node, const wxString& item) const; + // Tells all IDranges that they're now complete, and can create their IDs + void FinaliseRanges(const wxXmlNode* node) const; + // Searches for a known IdRange matching 'name', returning its index or -1 + int Find(const wxString& rangename) const; + +protected: + wxIdRange* FindRangeForItem(const wxXmlNode* node, + const wxString& item, + wxString& value) const; + wxVector m_IdRanges; + +private: + static wxIdRangeManager *ms_instance; +}; + namespace { @@ -90,7 +185,7 @@ const char *ATTR_INPUT_FILENAME = "__wx:filename"; // helper to get filename corresponding to an XML node wxString -GetFileNameFromNode(wxXmlNode *node, const wxXmlResourceDataRecords& files) +GetFileNameFromNode(const 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' @@ -250,6 +345,8 @@ bool wxXmlResource::Load(const wxString& filemask_) { wxString filemask = ConvertFileNameToURL(filemask_); + bool allOK = true; + #if wxUSE_FILESYSTEM wxFileSystem fsys; # define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE) @@ -271,14 +368,16 @@ bool wxXmlResource::Load(const wxString& filemask_) if ( IsArchive(fnd) ) { if ( !Load(fnd + wxT("#zip:*.xrc")) ) - return false; + allOK = false; } else // a single resource URL #endif // wxUSE_FILESYSTEM { - wxXmlResourceDataRecord *drec = new wxXmlResourceDataRecord; - drec->File = fnd; - Data().push_back(drec); + wxXmlDocument * const doc = DoLoadFile(fnd); + if ( !doc ) + allOK = false; + else + Data().push_back(new wxXmlResourceDataRecord(fnd, doc)); } fnd = wxXmlFindNext; @@ -286,7 +385,7 @@ bool wxXmlResource::Load(const wxString& filemask_) # undef wxXmlFindFirst # undef wxXmlFindNext - return UpdateResources(); + return allOK; } bool wxXmlResource::Unload(const wxString& filename) @@ -331,16 +430,18 @@ bool wxXmlResource::Unload(const wxString& filename) } -IMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject) - void wxXmlResource::AddHandler(wxXmlResourceHandler *handler) { + wxXmlResourceHandlerImpl *impl = new wxXmlResourceHandlerImpl(handler); + handler->SetImpl(impl); m_handlers.push_back(handler); handler->SetParentResource(this); } void wxXmlResource::InsertHandler(wxXmlResourceHandler *handler) { + wxXmlResourceHandlerImpl *impl = new wxXmlResourceHandlerImpl(handler); + handler->SetImpl(impl); m_handlers.insert(m_handlers.begin(), handler); handler->SetParentResource(this); } @@ -431,14 +532,27 @@ wxIcon wxXmlResource::LoadIcon(const wxString& name) } -wxObject *wxXmlResource::LoadObject(wxWindow *parent, const wxString& name, const wxString& classname) +wxObject * +wxXmlResource::DoLoadObject(wxWindow *parent, + const wxString& name, + const wxString& classname, + bool recursive) { - return CreateResFromNode(FindResource(name, classname), parent, NULL); + wxXmlNode * const node = FindResource(name, classname, recursive); + + return node ? DoCreateResFromNode(*node, parent, NULL) : NULL; } -bool wxXmlResource::LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, const wxString& classname) +bool +wxXmlResource::DoLoadObject(wxObject *instance, + wxWindow *parent, + const wxString& name, + const wxString& classname, + bool recursive) { - return CreateResFromNode(FindResource(name, classname), parent, instance) != NULL; + wxXmlNode * const node = FindResource(name, classname, recursive); + + return node && DoCreateResFromNode(*node, parent, instance) != NULL; } @@ -507,136 +621,162 @@ static void ProcessPlatformProperty(wxXmlNode *node) } } +static void PreprocessForIdRanges(wxXmlNode *rootnode) +{ + // First go through the top level, looking for the names of ID ranges + // as processing items is a lot easier if names are already known + wxXmlNode *c = rootnode->GetChildren(); + while (c) + { + if (c->GetName() == wxT("ids-range")) + wxIdRangeManager::Get()->AddRange(c); + c = c->GetNext(); + } + // Next, examine every 'name' for the '[' that denotes an ID in a range + c = rootnode->GetChildren(); + while (c) + { + wxString name = c->GetAttribute(wxT("name")); + if (name.find('[') != wxString::npos) + wxIdRangeManager::Get()->NotifyRangeOfItem(rootnode, name); + + // Do any children by recursion, then proceed to the next sibling + PreprocessForIdRanges(c); + c = c->GetNext(); + } +} bool wxXmlResource::UpdateResources() { bool rt = true; - bool modif; -# if wxUSE_FILESYSTEM - wxFSFile *file = NULL; - wxUnusedVar(file); - wxFileSystem fsys; -# endif - - wxString encoding(wxT("UTF-8")); -#if !wxUSE_UNICODE && wxUSE_INTL - if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 ) - { - // In case we are not using wxLocale to translate strings, convert the - // strings GUI's charset. This must not be done when wxXRC_USE_LOCALE - // is on, because it could break wxGetTranslation lookup. - encoding = wxLocale::GetSystemEncodingName(); - } -#endif for ( wxXmlResourceDataRecords::iterator i = Data().begin(); i != Data().end(); ++i ) { wxXmlResourceDataRecord* const rec = *i; - modif = (rec->Doc == NULL); + // Check if we need to reload this one. + + // We never do it if this flag is specified. + if ( m_flags & wxXRC_NO_RELOADING ) + continue; - if (!modif && !(m_flags & wxXRC_NO_RELOADING)) + // Otherwise check its modification time if we can. +#if wxUSE_DATETIME + const wxDateTime lastModTime = GetXRCFileModTime(rec->File); + + if ( lastModTime.IsValid() && lastModTime <= rec->Time ) +#else // !wxUSE_DATETIME + // Never reload the file contents: we can't know whether it changed or + // not in this build configuration and it would be unexpected and + // counter-productive to get a performance hit (due to constant + // reloading of XRC files) in a minimal wx build which is presumably + // used because of resource constraints of the current platform. +#endif // wxUSE_DATETIME/!wxUSE_DATETIME { -# if wxUSE_FILESYSTEM - file = fsys.OpenFile(rec->File); -# if wxUSE_DATETIME - modif = file && file->GetModificationTime() > rec->Time; -# else // wxUSE_DATETIME - modif = true; -# endif // wxUSE_DATETIME - if (!file) - { - wxLogError(_("Cannot open file '%s'."), rec->File); - rt = false; - } - wxDELETE(file); - wxUnusedVar(file); -# else // wxUSE_FILESYSTEM -# if wxUSE_DATETIME - modif = wxDateTime(wxFileModificationTime(rec->File)) > rec->Time; -# else // wxUSE_DATETIME - modif = true; -# endif // wxUSE_DATETIME -# endif // wxUSE_FILESYSTEM + // No need to reload, the file wasn't modified since we did it + // last. + continue; } - if (modif) + wxXmlDocument * const doc = DoLoadFile(rec->File); + if ( !doc ) { - wxLogTrace(wxT("xrc"), wxT("opening file '%s'"), rec->File); + // Notice that we keep the old XML document: it seems better to + // preserve it instead of throwing it away if we have nothing to + // replace it with. + rt = false; + continue; + } - wxInputStream *stream = NULL; + // Replace the old resource contents with the new one. + delete rec->Doc; + rec->Doc = doc; -# if wxUSE_FILESYSTEM - file = fsys.OpenFile(rec->File); - if (file) - stream = file->GetStream(); -# else - stream = new wxFileInputStream(rec->File); -# endif + // And, now that we loaded it successfully, update the last load time. +#if wxUSE_DATETIME + rec->Time = lastModTime.IsValid() ? lastModTime : wxDateTime::Now(); +#endif // wxUSE_DATETIME + } - if (stream) - { - delete rec->Doc; - rec->Doc = new wxXmlDocument; - } - if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding)) - { - wxLogError(_("Cannot load resources from file '%s'."), - rec->File); - wxDELETE(rec->Doc); - rt = false; - } - else if (rec->Doc->GetRoot()->GetName() != wxT("resource")) - { - ReportError - ( - rec->Doc->GetRoot(), - "invalid XRC resource, doesn't have root node " - ); - wxDELETE(rec->Doc); - rt = false; - } - else - { - long version; - int v1, v2, v3, v4; - wxString verstr = rec->Doc->GetRoot()->GetAttribute( - wxT("version"), wxT("0.0.0.0")); - if (wxSscanf(verstr.c_str(), wxT("%i.%i.%i.%i"), - &v1, &v2, &v3, &v4) == 4) - version = v1*256*256*256+v2*256*256+v3*256+v4; - else - version = 0; - if (m_version == -1) - m_version = version; - if (m_version != version) - { - wxLogError("Resource files must have same version number."); - rt = false; - } + return rt; +} + +wxXmlDocument *wxXmlResource::DoLoadFile(const wxString& filename) +{ + wxLogTrace(wxT("xrc"), wxT("opening file '%s'"), filename); + + wxInputStream *stream = NULL; - ProcessPlatformProperty(rec->Doc->GetRoot()); -#if wxUSE_DATETIME #if wxUSE_FILESYSTEM - rec->Time = file->GetModificationTime(); -#else // wxUSE_FILESYSTEM - rec->Time = wxDateTime(wxFileModificationTime(rec->File)); -#endif // wxUSE_FILESYSTEM -#endif // wxUSE_DATETIME - } + wxFileSystem fsys; + wxScopedPtr file(fsys.OpenFile(filename)); + if (file) + { + // Notice that we don't have ownership of the stream in this case, it + // remains owned by wxFSFile. + stream = file->GetStream(); + } +#else // !wxUSE_FILESYSTEM + wxFileInputStream fstream(filename); + stream = &fstream; +#endif // wxUSE_FILESYSTEM/!wxUSE_FILESYSTEM -# if wxUSE_FILESYSTEM - wxDELETE(file); - wxUnusedVar(file); -# else - wxDELETE(stream); -# endif - } + if ( !stream || !stream->IsOk() ) + { + wxLogError(_("Cannot open resources file '%s'."), filename); + return NULL; } - return rt; + wxString encoding(wxT("UTF-8")); +#if !wxUSE_UNICODE && wxUSE_INTL + if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 ) + { + // In case we are not using wxLocale to translate strings, convert the + // strings GUI's charset. This must not be done when wxXRC_USE_LOCALE + // is on, because it could break wxGetTranslation lookup. + encoding = wxLocale::GetSystemEncodingName(); + } +#endif + + wxScopedPtr doc(new wxXmlDocument); + if (!doc->Load(*stream, encoding)) + { + wxLogError(_("Cannot load resources from file '%s'."), filename); + return NULL; + } + + wxXmlNode * const root = doc->GetRoot(); + if (root->GetName() != wxT("resource")) + { + ReportError + ( + root, + "invalid XRC resource, doesn't have root node " + ); + return NULL; + } + + long version; + int v1, v2, v3, v4; + wxString verstr = root->GetAttribute(wxT("version"), wxT("0.0.0.0")); + if (wxSscanf(verstr, wxT("%i.%i.%i.%i"), &v1, &v2, &v3, &v4) == 4) + version = v1*256*256*256+v2*256*256+v3*256+v4; + else + version = 0; + if (m_version == -1) + m_version = version; + if (m_version != version) + { + wxLogWarning("Resource files must have same version number."); + } + + ProcessPlatformProperty(root); + PreprocessForIdRanges(root); + wxIdRangeManager::Get()->FinaliseRanges(root); + + return doc.release(); } wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent, @@ -731,7 +871,7 @@ wxXmlResource::GetResourceNodeAndLocation(const wxString& name, bool recursive, wxString *path) const { - // ensure everything is up-to-date: this is needed to support on-remand + // ensure everything is up-to-date: this is needed to support on-demand // reloading of XRC files const_cast(this)->UpdateResources(); @@ -819,23 +959,23 @@ static void MergeNodesOver(wxXmlNode& dest, wxXmlNode& overwriteWith, dest.SetContent(overwriteWith.GetContent()); } -wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, - wxObject *instance, - wxXmlResourceHandler *handlerToUse) +wxObject * +wxXmlResource::DoCreateResFromNode(wxXmlNode& node, + wxObject *parent, + wxObject *instance, + wxXmlResourceHandler *handlerToUse) { - if (node == NULL) return NULL; - // handling of referenced resource - if ( node->GetName() == wxT("object_ref") ) + if ( node.GetName() == wxT("object_ref") ) { - wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString); + wxString refName = node.GetAttribute(wxT("ref"), wxEmptyString); wxXmlNode* refNode = FindResource(refName, wxEmptyString, true); if ( !refNode ) { ReportError ( - node, + &node, wxString::Format ( "referenced object node with ref=\"%s\" not found", @@ -845,14 +985,17 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, return NULL; } - if ( !node->GetChildren() ) + const bool hasOnlyRefAttr = node.GetAttributes() != NULL && + node.GetAttributes()->GetNext() == NULL; + + if ( hasOnlyRefAttr && !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(refNode, parent, instance); + return DoCreateResFromNode(*refNode, parent, instance); } else { @@ -862,47 +1005,367 @@ wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, // load the resource from result of the merge. wxXmlNode copy(*refNode); - MergeNodesOver(copy, *node, GetFileNameFromNode(node, Data())); + 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); + return DoCreateResFromNode(copy, parent, instance); } } if (handlerToUse) { - if (handlerToUse->CanHandle(node)) + if (handlerToUse->CanHandle(&node)) { - return handlerToUse->CreateResource(node, parent, instance); + return handlerToUse->CreateResource(&node, parent, instance); } } - else if (node->GetName() == wxT("object")) + else if (node.GetName() == wxT("object")) { for ( wxVector::iterator h = m_handlers.begin(); h != m_handlers.end(); ++h ) { wxXmlResourceHandler *handler = *h; - if (handler->CanHandle(node)) - return handler->CreateResource(node, parent, instance); + if (handler->CanHandle(&node)) + return handler->CreateResource(&node, parent, instance); } } ReportError ( - node, + &node, wxString::Format ( "no handler found for XML node \"%s\" (class \"%s\")", - node->GetName(), - node->GetAttribute("class", wxEmptyString) + node.GetName(), + node.GetAttribute("class", wxEmptyString) ) ); return NULL; } +wxIdRange::wxIdRange(const wxXmlNode* node, + const wxString& rname, + const wxString& startno, + const wxString& rsize) + : m_name(rname), + m_start(0), + m_size(0), + m_item_end_found(0), + m_finalised(0) +{ + long l; + if ( startno.ToLong(&l) ) + { + if ( l >= 0 ) + { + m_start = l; + } + else + { + wxXmlResource::Get()->ReportError + ( + node, + "a negative id-range start parameter was given" + ); + } + } + else + { + wxXmlResource::Get()->ReportError + ( + node, + "the id-range start parameter was malformed" + ); + } + + unsigned long ul; + if ( rsize.ToULong(&ul) ) + { + m_size = ul; + } + else + { + wxXmlResource::Get()->ReportError + ( + node, + "the id-range size parameter was malformed" + ); + } +} + +void wxIdRange::NoteItem(const wxXmlNode* node, const wxString& item) +{ + // Nothing gets added here, but the existence of each item is noted + // thus getting an accurate count. 'item' will be either an integer e.g. + // [0] [123]: will eventually create an XRCID as start+integer or [start] + // or [end] which are synonyms for [0] or [range_size-1] respectively. + wxString content(item.Mid(1, item.length()-2)); + + // Check that basename+item wasn't foo[] + if (content.empty()) + { + wxXmlResource::Get()->ReportError(node, "an empty id-range item found"); + return; + } + + if (content=="start") + { + // "start" means [0], so store that in the set + if (m_indices.count(0) == 0) + { + m_indices.insert(0); + } + else + { + wxXmlResource::Get()->ReportError + ( + node, + "duplicate id-range item found" + ); + } + } + else if (content=="end") + { + // We can't yet be certain which XRCID this will be equivalent to, so + // just note that there's an item with this name, in case we need to + // inc the range size + m_item_end_found = true; + } + else + { + // Anything else will be an integer, or rubbish + unsigned long l; + if ( content.ToULong(&l) ) + { + if (m_indices.count(l) == 0) + { + m_indices.insert(l); + // Check that this item wouldn't fall outside the current range + // extent + if (l >= m_size) + { + m_size = l + 1; + } + } + else + { + wxXmlResource::Get()->ReportError + ( + node, + "duplicate id-range item found" + ); + } + + } + else + { + wxXmlResource::Get()->ReportError + ( + node, + "an id-range item had a malformed index" + ); + } + } +} + +void wxIdRange::Finalise(const wxXmlNode* node) +{ + wxCHECK_RET( !IsFinalised(), + "Trying to finalise an already-finalised range" ); + + // Now we know about all the items, we can get an accurate range size + // Expand any requested range-size if there were more items than would fit + m_size = wxMax(m_size, m_indices.size()); + + // If an item is explicitly called foo[end], ensure it won't clash with + // another item + if ( m_item_end_found && m_indices.count(m_size-1) ) + ++m_size; + if (m_size == 0) + { + // This will happen if someone creates a range but no items in this xrc + // file Report the error and abort, but don't finalise, in case items + // appear later + wxXmlResource::Get()->ReportError + ( + node, + "trying to create an empty id-range" + ); + return; + } + + if (m_start==0) + { + // This is the usual case, where the user didn't specify a start ID + // So get the range using NewControlId(). + // + // NB: negative numbers, but NewControlId already returns the most + // negative + m_start = wxWindow::NewControlId(m_size); + wxCHECK_RET( m_start != wxID_NONE, + "insufficient IDs available to create range" ); + m_end = m_start + m_size - 1; + } + else + { + // The user already specified a start value, which must be positive + m_end = m_start + m_size - 1; + } + + // Create the XRCIDs + for (int i=m_start; i <= m_end; ++i) + { + // Ensure that we overwrite any existing value as otherwise + // wxXmlResource::Unload() followed by Load() wouldn't work correctly. + XRCID_Assign(m_name + wxString::Format("[%i]", i-m_start), i); + + wxLogTrace("xrcrange", + "integer = %i %s now returns %i", + i, + m_name + wxString::Format("[%i]", i-m_start), + XRCID((m_name + wxString::Format("[%i]", i-m_start)).mb_str())); + } + // and these special ones + XRCID_Assign(m_name + "[start]", m_start); + XRCID_Assign(m_name + "[end]", m_end); + wxLogTrace("xrcrange","%s[start] = %i %s[end] = %i", + m_name.mb_str(),XRCID(wxString(m_name+"[start]").mb_str()), + m_name.mb_str(),XRCID(wxString(m_name+"[end]").mb_str())); + + m_finalised = true; +} + +wxIdRangeManager *wxIdRangeManager::ms_instance = NULL; + +/*static*/ wxIdRangeManager *wxIdRangeManager::Get() +{ + if ( !ms_instance ) + ms_instance = new wxIdRangeManager; + return ms_instance; +} + +/*static*/ wxIdRangeManager *wxIdRangeManager::Set(wxIdRangeManager *res) +{ + wxIdRangeManager *old = ms_instance; + ms_instance = res; + return old; +} + +wxIdRangeManager::~wxIdRangeManager() +{ + for ( wxVector::iterator i = m_IdRanges.begin(); + i != m_IdRanges.end(); ++i ) + { + delete *i; + } + m_IdRanges.clear(); + + delete ms_instance; +} + +void wxIdRangeManager::AddRange(const wxXmlNode* node) +{ + wxString name = node->GetAttribute("name"); + wxString start = node->GetAttribute("start", "0"); + wxString size = node->GetAttribute("size", "0"); + if (name.empty()) + { + wxXmlResource::Get()->ReportError + ( + node, + "xrc file contains an id-range without a name" + ); + return; + } + + int index = Find(name); + if (index == wxNOT_FOUND) + { + wxLogTrace("xrcrange", + "Adding ID range, name=%s start=%s size=%s", + name, start, size); + + m_IdRanges.push_back(new wxIdRange(node, name, start, size)); + } + else + { + // There was already a range with this name. Let's hope this is + // from an Unload()/(re)Load(), not an unintentional duplication + wxLogTrace("xrcrange", + "Replacing ID range, name=%s start=%s size=%s", + name, start, size); + + wxIdRange* oldrange = m_IdRanges.at(index); + m_IdRanges.at(index) = new wxIdRange(node, name, start, size); + delete oldrange; + } +} + +wxIdRange * +wxIdRangeManager::FindRangeForItem(const wxXmlNode* node, + const wxString& item, + wxString& value) const +{ + wxString basename = item.BeforeFirst('['); + wxCHECK_MSG( !basename.empty(), NULL, + "an id-range item without a range name" ); + + int index = Find(basename); + if (index == wxNOT_FOUND) + { + // Don't assert just because we've found an unexpected foo[123] + // Someone might just want such a name, nothing to do with ranges + return NULL; + } + + value = item.Mid(basename.Len()); + if (value.at(value.length()-1)==']') + { + return m_IdRanges.at(index); + } + wxXmlResource::Get()->ReportError(node, "a malformed id-range item"); + return NULL; +} + +void +wxIdRangeManager::NotifyRangeOfItem(const wxXmlNode* node, + const wxString& item) const +{ + wxString value; + wxIdRange* range = FindRangeForItem(node, item, value); + if (range) + range->NoteItem(node, value); +} + +int wxIdRangeManager::Find(const wxString& rangename) const +{ + for ( int i=0; i < (int)m_IdRanges.size(); ++i ) + { + if (m_IdRanges.at(i)->GetName() == rangename) + return i; + } + + return wxNOT_FOUND; +} + +void wxIdRangeManager::FinaliseRanges(const wxXmlNode* node) const +{ + for ( wxVector::const_iterator i = m_IdRanges.begin(); + i != m_IdRanges.end(); ++i ) + { + // Check if this range has already been finalised. Quite possible, + // as FinaliseRanges() gets called for each .xrc file loaded + if (!(*i)->IsFinalised()) + { + wxLogTrace("xrcrange", "Finalising ID range %s", (*i)->GetName()); + (*i)->Finalise(node); + } + } +} + class wxXmlSubclassFactories : public wxVector { @@ -939,23 +1402,35 @@ public: -wxXmlResourceHandler::wxXmlResourceHandler() - : m_node(NULL), m_parent(NULL), m_instance(NULL), - m_parentAsWindow(NULL) -{} +wxXmlResourceHandlerImpl::wxXmlResourceHandlerImpl(wxXmlResourceHandler *handler) + :wxXmlResourceHandlerImplBase(handler) +{ +} + +wxObject *wxXmlResourceHandlerImpl::CreateResFromNode(wxXmlNode *node, + wxObject *parent, wxObject *instance) +{ + return m_handler->m_resource->CreateResFromNode(node, parent, instance); +} +#if wxUSE_FILESYSTEM +wxFileSystem& wxXmlResourceHandlerImpl::GetCurFileSystem() +{ + return m_handler->m_resource->GetCurFileSystem(); +} +#endif -wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance) +wxObject *wxXmlResourceHandlerImpl::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance) { - wxXmlNode *myNode = m_node; - wxString myClass = m_class; - wxObject *myParent = m_parent, *myInstance = m_instance; - wxWindow *myParentAW = m_parentAsWindow; + wxXmlNode *myNode = m_handler->m_node; + wxString myClass = m_handler->m_class; + wxObject *myParent = m_handler->m_parent, *myInstance = m_handler->m_instance; + wxWindow *myParentAW = m_handler->m_parentAsWindow; - m_instance = instance; - if (!m_instance && node->HasAttribute(wxT("subclass")) && - !(m_resource->GetFlags() & wxXRC_NO_SUBCLASSING)) + m_handler->m_instance = instance; + if (!m_handler->m_instance && node->HasAttribute(wxT("subclass")) && + !(m_handler->m_resource->GetFlags() & wxXRC_NO_SUBCLASSING)) { wxString subclass = node->GetAttribute(wxT("subclass"), wxEmptyString); if (!subclass.empty()) @@ -963,12 +1438,12 @@ wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent for (wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin(); i != wxXmlResource::ms_subclassFactories->end(); ++i) { - m_instance = (*i)->Create(subclass); - if (m_instance) + m_handler->m_instance = (*i)->Create(subclass); + if (m_handler->m_instance) break; } - if (!m_instance) + if (!m_handler->m_instance) { wxString name = node->GetAttribute(wxT("name"), wxEmptyString); ReportError @@ -984,61 +1459,28 @@ wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent } } - m_node = node; - m_class = node->GetAttribute(wxT("class"), wxEmptyString); - m_parent = parent; - m_parentAsWindow = wxDynamicCast(m_parent, wxWindow); + m_handler->m_node = node; + m_handler->m_class = node->GetAttribute(wxT("class"), wxEmptyString); + m_handler->m_parent = parent; + m_handler->m_parentAsWindow = wxDynamicCast(m_handler->m_parent, wxWindow); - wxObject *returned = DoCreateResource(); + wxObject *returned = GetHandler()->DoCreateResource(); - m_node = myNode; - m_class = myClass; - m_parent = myParent; m_parentAsWindow = myParentAW; - m_instance = myInstance; + m_handler->m_node = myNode; + m_handler->m_class = myClass; + m_handler->m_parent = myParent; m_handler->m_parentAsWindow = myParentAW; + m_handler->m_instance = myInstance; return returned; } - -void wxXmlResourceHandler::AddStyle(const wxString& name, int value) -{ - m_styleNames.Add(name); - m_styleValues.Add(value); -} - - - -void wxXmlResourceHandler::AddWindowStyles() -{ - XRC_ADD_STYLE(wxCLIP_CHILDREN); - - // the border styles all have the old and new names, recognize both for now - XRC_ADD_STYLE(wxSIMPLE_BORDER); XRC_ADD_STYLE(wxBORDER_SIMPLE); - XRC_ADD_STYLE(wxSUNKEN_BORDER); XRC_ADD_STYLE(wxBORDER_SUNKEN); - XRC_ADD_STYLE(wxDOUBLE_BORDER); XRC_ADD_STYLE(wxBORDER_DOUBLE); - XRC_ADD_STYLE(wxRAISED_BORDER); XRC_ADD_STYLE(wxBORDER_RAISED); - XRC_ADD_STYLE(wxSTATIC_BORDER); XRC_ADD_STYLE(wxBORDER_STATIC); - XRC_ADD_STYLE(wxNO_BORDER); XRC_ADD_STYLE(wxBORDER_NONE); - - XRC_ADD_STYLE(wxTRANSPARENT_WINDOW); - XRC_ADD_STYLE(wxWANTS_CHARS); - XRC_ADD_STYLE(wxTAB_TRAVERSAL); - XRC_ADD_STYLE(wxNO_FULL_REPAINT_ON_RESIZE); - XRC_ADD_STYLE(wxFULL_REPAINT_ON_RESIZE); - XRC_ADD_STYLE(wxALWAYS_SHOW_SB); - XRC_ADD_STYLE(wxWS_EX_BLOCK_EVENTS); - XRC_ADD_STYLE(wxWS_EX_VALIDATE_RECURSIVELY); -} - - - -bool wxXmlResourceHandler::HasParam(const wxString& param) +bool wxXmlResourceHandlerImpl::HasParam(const wxString& param) { return (GetParamNode(param) != NULL); } -int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults) +int wxXmlResourceHandlerImpl::GetStyle(const wxString& param, int defaults) { wxString s = GetParamValue(param); @@ -1051,10 +1493,10 @@ int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults) while (tkn.HasMoreTokens()) { fl = tkn.GetNextToken(); - index = m_styleNames.Index(fl); + index = m_handler->m_styleNames.Index(fl); if (index != wxNOT_FOUND) { - style |= m_styleValues[index]; + style |= m_handler->m_styleValues[index]; } else { @@ -1070,19 +1512,19 @@ int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults) -wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) +wxString wxXmlResourceHandlerImpl::GetText(const wxString& param, bool translate) { wxXmlNode *parNode = GetParamNode(param); wxString str1(GetNodeContent(parNode)); wxString str2; // "\\" wasn't translated to "\" prior to 2.5.3.0: - const bool escapeBackslash = (m_resource->CompareVersion(2,5,3,0) >= 0); + const bool escapeBackslash = (m_handler->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"). - const wxChar amp_char = (m_resource->CompareVersion(2,3,0,1) < 0) + const wxChar amp_char = (m_handler->m_resource->CompareVersion(2,3,0,1) < 0) ? '$' : '_'; for ( wxString::const_iterator dt = str1.begin(); dt != str1.end(); ++dt ) @@ -1091,7 +1533,7 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) // like "&File..." -- this is illegal in XML, so we use "_File..."): if ( *dt == amp_char ) { - if ( *(++dt) == amp_char ) + if ( dt+1 == str1.end() || *(++dt) == amp_char ) str2 << amp_char; else str2 << wxT('&') << *dt; @@ -1133,12 +1575,12 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) } } - if (m_resource->GetFlags() & wxXRC_USE_LOCALE) + if (m_handler->m_resource->GetFlags() & wxXRC_USE_LOCALE) { if (translate && parNode && parNode->GetAttribute(wxT("translate"), wxEmptyString) != wxT("0")) { - return wxGetTranslation(str2, m_resource->GetDomain()); + return wxGetTranslation(str2, m_handler->m_resource->GetDomain()); } else { @@ -1160,60 +1602,71 @@ wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate) -long wxXmlResourceHandler::GetLong(const wxString& param, long defaultv) +long wxXmlResourceHandlerImpl::GetLong(const wxString& param, long defaultv) { - long value; + long value = defaultv; wxString str1 = GetParamValue(param); - if (!str1.ToLong(&value)) - value = defaultv; + if (!str1.empty()) + { + if (!str1.ToLong(&value)) + { + ReportParamError + ( + param, + wxString::Format("invalid long specification \"%s\"", str1) + ); + } + } return value; } -float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv) +float wxXmlResourceHandlerImpl::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 - // - // 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)) - value = defaultv; + // strings in XRC always use C locale so make sure to use the + // locale-independent wxString::ToCDouble() and not ToDouble() which uses + // the current locale with a potentially different decimal point character + double value = defaultv; + if (!str.empty()) + { + if (!str.ToCDouble(&value)) + { + ReportParamError + ( + param, + wxString::Format("invalid float specification \"%s\"", str) + ); + } + } return wx_truncate_cast(float, value); } -int wxXmlResourceHandler::GetID() +int wxXmlResourceHandlerImpl::GetID() { return wxXmlResource::GetXRCID(GetName()); } -wxString wxXmlResourceHandler::GetName() +wxString wxXmlResourceHandlerImpl::GetName() { - return m_node->GetAttribute(wxT("name"), wxT("-1")); + return m_handler->m_node->GetAttribute(wxT("name"), wxT("-1")); } -bool wxXmlResourceHandler::GetBoolAttr(const wxString& attr, bool defaultv) +bool wxXmlResourceHandlerImpl::GetBoolAttr(const wxString& attr, bool defaultv) { wxString v; - return m_node->GetAttribute(attr, &v) ? v == '1' : defaultv; + return m_handler->m_node->GetAttribute(attr, &v) ? v == '1' : defaultv; } -bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv) +bool wxXmlResourceHandlerImpl::GetBool(const wxString& param, bool defaultv) { const wxString v = GetParamValue(param); @@ -1270,7 +1723,7 @@ static wxColour GetSystemColour(const wxString& name) return wxNullColour; } -wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& defaultv) +wxColour wxXmlResourceHandlerImpl::GetColour(const wxString& param, const wxColour& defaultv) { wxString v = GetParamValue(param); @@ -1285,7 +1738,7 @@ wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& // the colour doesn't use #RRGGBB format, check if it is symbolic // colour name: clr = GetSystemColour(v); - if (clr.Ok()) + if (clr.IsOk()) return clr; ReportParamError @@ -1330,7 +1783,7 @@ bool GetStockArtAttrs(const wxXmlNode *paramNode, } // anonymous namespace -wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param, +wxBitmap wxXmlResourceHandlerImpl::GetBitmap(const wxString& param, const wxArtClient& defaultArtClient, wxSize size) { @@ -1351,7 +1804,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param, return GetBitmap(node, defaultArtClient, size); } -wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node, +wxBitmap wxXmlResourceHandlerImpl::GetBitmap(const wxXmlNode* node, const wxArtClient& defaultArtClient, wxSize size) { @@ -1363,7 +1816,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node, art_id, art_client) ) { wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size)); - if ( stockArt.Ok() ) + if ( stockArt.IsOk() ) return stockArt; } @@ -1387,7 +1840,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node, wxImage img(name); #endif - if (!img.Ok()) + if (!img.IsOk()) { ReportParamError ( @@ -1401,7 +1854,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node, } -wxIcon wxXmlResourceHandler::GetIcon(const wxString& param, +wxIcon wxXmlResourceHandlerImpl::GetIcon(const wxString& param, const wxArtClient& defaultArtClient, wxSize size) { @@ -1419,7 +1872,7 @@ wxIcon wxXmlResourceHandler::GetIcon(const wxString& param, return GetIcon(node, defaultArtClient, size); } -wxIcon wxXmlResourceHandler::GetIcon(const wxXmlNode* node, +wxIcon wxXmlResourceHandlerImpl::GetIcon(const wxXmlNode* node, const wxArtClient& defaultArtClient, wxSize size) { @@ -1429,7 +1882,7 @@ wxIcon wxXmlResourceHandler::GetIcon(const wxXmlNode* node, } -wxIconBundle wxXmlResourceHandler::GetIconBundle(const wxString& param, +wxIconBundle wxXmlResourceHandlerImpl::GetIconBundle(const wxString& param, const wxArtClient& defaultArtClient) { wxString art_id, art_client; @@ -1477,51 +1930,59 @@ wxIconBundle wxXmlResourceHandler::GetIconBundle(const wxString& param, } -wxImageList *wxXmlResourceHandler::GetImageList(const wxString& param) +wxImageList *wxXmlResourceHandlerImpl::GetImageList(const wxString& param) { wxXmlNode * const imagelist_node = GetParamNode(param); if ( !imagelist_node ) return NULL; - wxXmlNode * const oldnode = m_node; - m_node = imagelist_node; + wxXmlNode * const oldnode = m_handler->m_node; + m_handler->m_node = imagelist_node; - // size + // Get the size if we have it, otherwise we will use the size of the first + // list element. 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 + // Start adding images, we'll create the image list when adding the first + // one. + wxImageList * imagelist = NULL; wxString parambitmap = wxT("bitmap"); if ( HasParam(parambitmap) ) { - wxXmlNode *n = m_node->GetChildren(); + wxXmlNode *n = m_handler->m_node->GetChildren(); while (n) { if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == parambitmap) { + wxIcon icon = GetIcon(n, wxART_OTHER, size); + if ( !imagelist ) + { + // We need the real image list size to create it. + if ( size == wxDefaultSize ) + size = icon.GetSize(); + + // We use the mask by default. + bool mask = GetBool(wxS("mask"), true); + + imagelist = new wxImageList(size.x, size.y, mask); + } + // add icon instead of bitmap to keep the bitmap mask - imagelist->Add(GetIcon(n)); + imagelist->Add(icon); } n = n->GetNext(); } } - m_node = oldnode; + m_handler->m_node = oldnode; return imagelist; } -wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param) +wxXmlNode *wxXmlResourceHandlerImpl::GetParamNode(const wxString& param) { - wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!")); + wxCHECK_MSG(m_handler->m_node, NULL, wxT("You can't access handler data before it was initialized!")); - wxXmlNode *n = m_node->GetChildren(); + wxXmlNode *n = m_handler->m_node->GetChildren(); while (n) { @@ -1540,14 +2001,14 @@ wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param) return NULL; } -bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname) +bool wxXmlResourceHandlerImpl::IsOfClass(wxXmlNode *node, const wxString& classname) const { - return node->GetAttribute(wxT("class"), wxEmptyString) == classname; + return node->GetAttribute(wxT("class")) == classname; } -wxString wxXmlResourceHandler::GetNodeContent(const wxXmlNode *node) +wxString wxXmlResourceHandlerImpl::GetNodeContent(const wxXmlNode *node) { const wxXmlNode *n = node; if (n == NULL) return wxEmptyString; @@ -1565,21 +2026,21 @@ wxString wxXmlResourceHandler::GetNodeContent(const wxXmlNode *node) -wxString wxXmlResourceHandler::GetParamValue(const wxString& param) +wxString wxXmlResourceHandlerImpl::GetParamValue(const wxString& param) { if (param.empty()) - return GetNodeContent(m_node); + return GetNodeContent(m_handler->m_node); else return GetNodeContent(GetParamNode(param)); } -wxString wxXmlResourceHandler::GetParamValue(const wxXmlNode* node) +wxString wxXmlResourceHandlerImpl::GetParamValue(const wxXmlNode* node) { return GetNodeContent(node); } -wxSize wxXmlResourceHandler::GetSize(const wxString& param, +wxSize wxXmlResourceHandlerImpl::GetSize(const wxString& param, wxWindow *windowToUse) { wxString s = GetParamValue(param); @@ -1607,9 +2068,9 @@ wxSize wxXmlResourceHandler::GetSize(const wxString& param, { return wxDLG_UNIT(windowToUse, wxSize(sx, sy)); } - else if (m_parentAsWindow) + else if (m_handler->m_parentAsWindow) { - return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, sy)); + return wxDLG_UNIT(m_handler->m_parentAsWindow, wxSize(sx, sy)); } else { @@ -1627,7 +2088,7 @@ wxSize wxXmlResourceHandler::GetSize(const wxString& param, -wxPoint wxXmlResourceHandler::GetPosition(const wxString& param) +wxPoint wxXmlResourceHandlerImpl::GetPosition(const wxString& param) { wxSize sz = GetSize(param); return wxPoint(sz.x, sz.y); @@ -1635,7 +2096,7 @@ wxPoint wxXmlResourceHandler::GetPosition(const wxString& param) -wxCoord wxXmlResourceHandler::GetDimension(const wxString& param, +wxCoord wxXmlResourceHandlerImpl::GetDimension(const wxString& param, wxCoord defaultv, wxWindow *windowToUse) { @@ -1663,9 +2124,9 @@ wxCoord wxXmlResourceHandler::GetDimension(const wxString& param, { return wxDLG_UNIT(windowToUse, wxSize(sx, 0)).x; } - else if (m_parentAsWindow) + else if (m_handler->m_parentAsWindow) { - return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, 0)).x; + return wxDLG_UNIT(m_handler->m_parentAsWindow, wxSize(sx, 0)).x; } else { @@ -1681,6 +2142,40 @@ wxCoord wxXmlResourceHandler::GetDimension(const wxString& param, return sx; } +wxDirection +wxXmlResourceHandlerImpl::GetDirection(const wxString& param, wxDirection dirDefault) +{ + wxDirection dir; + + const wxString dirstr = GetParamValue(param); + if ( dirstr.empty() ) + dir = dirDefault; + else if ( dirstr == "wxLEFT" ) + dir = wxLEFT; + else if ( dirstr == "wxRIGHT" ) + dir = wxRIGHT; + else if ( dirstr == "wxTOP" ) + dir = wxTOP; + else if ( dirstr == "wxBOTTOM" ) + dir = wxBOTTOM; + else + { + ReportError + ( + GetParamNode(param), + wxString::Format + ( + "Invalid direction \"%s\": must be one of " + "wxLEFT|wxRIGHT|wxTOP|wxBOTTOM.", + dirstr + ) + ); + + dir = dirDefault; + } + + return dir; +} // Get system font index using indexname static wxFont GetSystemFont(const wxString& name) @@ -1702,7 +2197,7 @@ static wxFont GetSystemFont(const wxString& name) return wxNullFont; } -wxFont wxXmlResourceHandler::GetFont(const wxString& param) +wxFont wxXmlResourceHandlerImpl::GetFont(const wxString& param, wxWindow* parent) { wxXmlNode *font_node = GetParamNode(param); if (font_node == NULL) @@ -1712,8 +2207,8 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) return wxNullFont; } - wxXmlNode *oldnode = m_node; - m_node = font_node; + wxXmlNode *oldnode = m_handler->m_node; + m_handler->m_node = font_node; // font attributes: @@ -1733,6 +2228,14 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) istyle = wxITALIC; else if (style == wxT("slant")) istyle = wxSLANT; + else if (style != wxT("normal")) + { + ReportParamError + ( + param, + wxString::Format("unknown font style \"%s\"", style) + ); + } } // weight @@ -1745,6 +2248,14 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) iweight = wxBOLD; else if (weight == wxT("light")) iweight = wxLIGHT; + else if (weight != wxT("normal")) + { + ReportParamError + ( + param, + wxString::Format("unknown font weight \"%s\"", weight) + ); + } } // underline @@ -1763,6 +2274,14 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) else if (family == wxT("swiss")) ifamily = wxSWISS; else if (family == wxT("modern")) ifamily = wxMODERN; else if (family == wxT("teletype")) ifamily = wxTELETYPE; + else + { + ReportParamError + ( + param, + wxString::Format("unknown font family \"%s\"", family) + ); + } } @@ -1793,6 +2312,7 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) // encoding wxFontEncoding enc = wxFONTENCODING_DEFAULT; bool hasEncoding = HasParam(wxT("encoding")); +#if wxUSE_FONTMAP if (hasEncoding) { wxString encoding = GetParamValue(wxT("encoding")); @@ -1802,14 +2322,52 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) if (enc == wxFONTENCODING_SYSTEM) enc = wxFONTENCODING_DEFAULT; } +#endif // wxUSE_FONTMAP + + wxFont font; // is this font based on a system font? - wxFont font = GetSystemFont(GetParamValue(wxT("sysfont"))); + if (HasParam(wxT("sysfont"))) + { + font = GetSystemFont(GetParamValue(wxT("sysfont"))); + if (HasParam(wxT("inherit"))) + { + ReportParamError + ( + param, + "double specification of \"sysfont\" and \"inherit\"" + ); + } + } + // or should the font of the widget be used? + else if (GetBool(wxT("inherit"), false)) + { + if (parent) + font = parent->GetFont(); + else + { + ReportParamError + ( + param, + "no parent window specified to derive the font from" + ); + } + } - if (font.Ok()) + if (font.IsOk()) { if (hasSize && isize != -1) + { font.SetPointSize(isize); + if (HasParam(wxT("relativesize"))) + { + ReportParamError + ( + param, + "double specification of \"size\" and \"relativesize\"" + ); + } + } else if (HasParam(wxT("relativesize"))) font.SetPointSize(int(font.GetPointSize() * GetFloat(wxT("relativesize")))); @@ -1834,12 +2392,12 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param) underlined, facename, enc); } - m_node = oldnode; + m_handler->m_node = oldnode; return font; } -void wxXmlResourceHandler::SetupWindow(wxWindow *wnd) +void wxXmlResourceHandlerImpl::SetupWindow(wxWindow *wnd) { //FIXME : add cursor @@ -1867,36 +2425,36 @@ void wxXmlResourceHandler::SetupWindow(wxWindow *wnd) wnd->SetToolTip(GetText(wxT("tooltip"))); #endif if (HasParam(wxT("font"))) - wnd->SetFont(GetFont(wxT("font"))); + wnd->SetFont(GetFont(wxT("font"), wnd)); if (HasParam(wxT("ownfont"))) - wnd->SetOwnFont(GetFont(wxT("ownfont"))); + wnd->SetOwnFont(GetFont(wxT("ownfont"), wnd)); if (HasParam(wxT("help"))) wnd->SetHelpText(GetText(wxT("help"))); } -void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only) +void wxXmlResourceHandlerImpl::CreateChildren(wxObject *parent, bool this_hnd_only) { - for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() ) + for ( wxXmlNode *n = m_handler->m_node->GetChildren(); n; n = n->GetNext() ) { if ( IsObjectNode(n) ) { - m_resource->CreateResFromNode(n, parent, NULL, - this_hnd_only ? this : NULL); - } + m_handler->m_resource->DoCreateResFromNode(*n, parent, NULL, + this_hnd_only ? this->GetHandler() : NULL); + } } } -void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode) +void wxXmlResourceHandlerImpl::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode) { wxXmlNode *root; - if (rootnode == NULL) root = m_node; else root = rootnode; + if (rootnode == NULL) root = m_handler->m_node; else root = rootnode; wxXmlNode *n = root->GetChildren(); while (n) { - if (n->GetType() == wxXML_ELEMENT_NODE && CanHandle(n)) + if (n->GetType() == wxXML_ELEMENT_NODE && GetHandler()->CanHandle(n)) { CreateResource(n, parent, NULL); } @@ -1909,24 +2467,24 @@ void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode * // errors reporting //----------------------------------------------------------------------------- -void wxXmlResourceHandler::ReportError(const wxString& message) +void wxXmlResourceHandlerImpl::ReportError(const wxString& message) { - m_resource->ReportError(m_node, message); + m_handler->m_resource->ReportError(m_handler->m_node, message); } -void wxXmlResourceHandler::ReportError(wxXmlNode *context, +void wxXmlResourceHandlerImpl::ReportError(wxXmlNode *context, const wxString& message) { - m_resource->ReportError(context ? context : m_node, message); + m_handler->m_resource->ReportError(context ? context : m_handler->m_node, message); } -void wxXmlResourceHandler::ReportParamError(const wxString& param, +void wxXmlResourceHandlerImpl::ReportParamError(const wxString& param, const wxString& message) { - m_resource->ReportError(GetParamNode(param), message); + m_handler->m_resource->ReportError(GetParamNode(param), message); } -void wxXmlResource::ReportError(wxXmlNode *context, const wxString& message) +void wxXmlResource::ReportError(const wxXmlNode *context, const wxString& message) { if ( !context ) { @@ -1942,7 +2500,7 @@ void wxXmlResource::ReportError(wxXmlNode *context, const wxString& message) DoReportError(filename, context, message); } -void wxXmlResource::DoReportError(const wxString& xrcFile, wxXmlNode *position, +void wxXmlResource::DoReportError(const wxString& xrcFile, const wxXmlNode *position, const wxString& message) { const int line = position ? position->GetLineNumber() : -1; @@ -1978,13 +2536,48 @@ struct XRCID_record static XRCID_record *XRCID_Records[XRCID_TABLE_SIZE] = {NULL}; -static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE) +// Extremely simplistic hash function which probably ought to be replaced with +// wxStringHash::stringHash(). +static inline unsigned XRCIdHash(const char *str_id) { - int index = 0; + unsigned index = 0; - for (const char *c = str_id; *c != '\0'; c++) index += (int)*c; + for (const char *c = str_id; *c != '\0'; c++) index += (unsigned int)*c; index %= XRCID_TABLE_SIZE; + return index; +} + +static void XRCID_Assign(const wxString& str_id, int value) +{ + const wxCharBuffer buf_id(str_id.mb_str()); + const unsigned index = XRCIdHash(buf_id); + + + XRCID_record *oldrec = NULL; + for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next) + { + if (wxStrcmp(rec->key, buf_id) == 0) + { + rec->id = value; + return; + } + oldrec = rec; + } + + XRCID_record **rec_var = (oldrec == NULL) ? + &XRCID_Records[index] : &oldrec->next; + *rec_var = new XRCID_record; + (*rec_var)->key = wxStrdup(str_id); + (*rec_var)->id = value; + (*rec_var)->next = NULL; +} + +static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE) +{ + const unsigned index = XRCIdHash(str_id); + + XRCID_record *oldrec = NULL; for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next) { @@ -2021,58 +2614,13 @@ static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE) return (*rec_var)->id; } -static void AddStdXRCID_Records(); - -/*static*/ -int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found) -{ - static bool s_stdIDsAdded = false; - - if ( !s_stdIDsAdded ) - { - s_stdIDsAdded = true; - AddStdXRCID_Records(); - } - - 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) +namespace { - if (rec) - { - CleanXRCID_Record(rec->next); - - free(rec->key); - delete rec; - } -} -static void CleanXRCID_Records() -{ - for (int i = 0; i < XRCID_TABLE_SIZE; i++) - { - CleanXRCID_Record(XRCID_Records[i]); - XRCID_Records[i] = NULL; - } -} +// flag indicating whether standard XRC ids were already initialized +static bool gs_stdIDsAdded = false; -static void AddStdXRCID_Records() +void AddStdXRCID_Records() { #define stdID(id) XRCID_Lookup(#id, id) stdID(-1); @@ -2096,11 +2644,14 @@ static void AddStdXRCID_Records() stdID(wxID_PREVIEW); stdID(wxID_ABOUT); stdID(wxID_HELP_CONTENTS); + stdID(wxID_HELP_INDEX), + stdID(wxID_HELP_SEARCH), stdID(wxID_HELP_COMMANDS); stdID(wxID_HELP_PROCEDURES); stdID(wxID_HELP_CONTEXT); stdID(wxID_CLOSE_ALL); stdID(wxID_PREFERENCES); + stdID(wxID_EDIT); stdID(wxID_CUT); stdID(wxID_COPY); @@ -2113,6 +2664,7 @@ static void AddStdXRCID_Records() stdID(wxID_REPLACE); stdID(wxID_REPLACE_ALL); stdID(wxID_PROPERTIES); + stdID(wxID_VIEW_DETAILS); stdID(wxID_VIEW_LARGEICONS); stdID(wxID_VIEW_SMALLICONS); @@ -2121,6 +2673,8 @@ static void AddStdXRCID_Records() stdID(wxID_VIEW_SORTNAME); stdID(wxID_VIEW_SORTSIZE); stdID(wxID_VIEW_SORTTYPE); + + stdID(wxID_FILE1); stdID(wxID_FILE2); stdID(wxID_FILE3); @@ -2130,6 +2684,8 @@ static void AddStdXRCID_Records() stdID(wxID_FILE7); stdID(wxID_FILE8); stdID(wxID_FILE9); + + stdID(wxID_OK); stdID(wxID_CANCEL); stdID(wxID_APPLY); @@ -2150,12 +2706,14 @@ static void AddStdXRCID_Records() stdID(wxID_IGNORE); stdID(wxID_ADD); stdID(wxID_REMOVE); + stdID(wxID_UP); stdID(wxID_DOWN); stdID(wxID_HOME); stdID(wxID_REFRESH); stdID(wxID_STOP); stdID(wxID_INDEX); + stdID(wxID_BOLD); stdID(wxID_ITALIC); stdID(wxID_JUSTIFY_CENTER); @@ -2171,13 +2729,6 @@ static void AddStdXRCID_Records() stdID(wxID_ZOOM_OUT); stdID(wxID_UNDELETE); stdID(wxID_REVERT_TO_SAVED); - stdID(wxID_SYSTEM_MENU); - stdID(wxID_CLOSE_FRAME); - stdID(wxID_MOVE_FRAME); - stdID(wxID_RESIZE_FRAME); - stdID(wxID_MAXIMIZE_FRAME); - stdID(wxID_ICONIZE_FRAME); - stdID(wxID_RESTORE_FRAME); stdID(wxID_CDROM); stdID(wxID_CONVERT); stdID(wxID_EXECUTE); @@ -2197,11 +2748,77 @@ static void AddStdXRCID_Records() stdID(wxID_SPELL_CHECK); stdID(wxID_STRIKETHROUGH); + + stdID(wxID_SYSTEM_MENU); + stdID(wxID_CLOSE_FRAME); + stdID(wxID_MOVE_FRAME); + stdID(wxID_RESIZE_FRAME); + stdID(wxID_MAXIMIZE_FRAME); + stdID(wxID_ICONIZE_FRAME); + stdID(wxID_RESTORE_FRAME); + + + + stdID(wxID_MDI_WINDOW_CASCADE); + stdID(wxID_MDI_WINDOW_TILE_HORZ); + stdID(wxID_MDI_WINDOW_TILE_VERT); + stdID(wxID_MDI_WINDOW_ARRANGE_ICONS); + stdID(wxID_MDI_WINDOW_PREV); + stdID(wxID_MDI_WINDOW_NEXT); #undef stdID } +} // anonymous namespace + + +/*static*/ +int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found) +{ + if ( !gs_stdIDsAdded ) + { + gs_stdIDsAdded = true; + AddStdXRCID_Records(); + } + + 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; + } +} +static void CleanXRCID_Records() +{ + for (int i = 0; i < XRCID_TABLE_SIZE; i++) + { + CleanXRCID_Record(XRCID_Records[i]); + XRCID_Records[i] = NULL; + } + gs_stdIDsAdded = false; +} //----------------------------------------------------------------------------- @@ -2232,6 +2849,7 @@ public: void OnExit() { delete wxXmlResource::Set(NULL); + delete wxIdRangeManager::Set(NULL); if(wxXmlResource::ms_subclassFactories) { for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin(); @@ -2253,8 +2871,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule) void wxXmlInitResourceModule() { wxModule* module = new wxXmlResourceModule; - module->Init(); wxModule::RegisterModule(module); + wxModule::InitializeModules(); } #endif // wxUSE_XRC