]> git.saurik.com Git - wxWidgets.git/blobdiff - src/xrc/xmlres.cpp
Add missing WXK constants for the control keys
[wxWidgets.git] / src / xrc / xmlres.cpp
index cc3649c9c3597b82b1a623e70ac50824f92437a4..a600a58db3798bf7a3c74c16ce2ea06a003574fc 100644 (file)
 #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<wxFSFile> 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 +98,8 @@ public:
 #if wxUSE_DATETIME
     wxDateTime Time;
 #endif
+
+    wxDECLARE_NO_COPY_CLASS(wxXmlResourceDataRecord);
 };
 
 class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord*>
@@ -71,6 +107,66 @@ class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord*>
     // 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<wxIdRange*> m_IdRanges;
+
+private:
+    static wxIdRangeManager *ms_instance;
+};
+
 namespace
 {
 
@@ -250,6 +346,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 +369,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 +386,7 @@ bool wxXmlResource::Load(const wxString& filemask_)
 #   undef wxXmlFindFirst
 #   undef wxXmlFindNext
 
-    return UpdateResources();
+    return allOK;
 }
 
 bool wxXmlResource::Unload(const wxString& filename)
@@ -331,16 +431,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);
 }
@@ -520,136 +622,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.
 
-        if (!modif && !(m_flags & wxXRC_NO_RELOADING))
+        // We never do it if this flag is specified.
+        if ( m_flags & wxXRC_NO_RELOADING )
+            continue;
+
+        // 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 <resource>"
-                );
-                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<wxFSFile> 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<wxXmlDocument> 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 <resource>"
+        );
+        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,
@@ -744,7 +872,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<wxXmlResource *>(this)->UpdateResources();
 
@@ -858,7 +986,10 @@ wxXmlResource::DoCreateResFromNode(wxXmlNode& node,
             return NULL;
         }
 
-        if ( !node.GetChildren() )
+        const bool hasOnlyRefAttr = node.GetAttributes() != NULL &&
+                                    node.GetAttributes()->GetNext() == NULL;
+
+        if ( hasOnlyRefAttr && !node.GetChildren() )
         {
             // In the typical, simple case, <object_ref> is used to link
             // to another node and doesn't have any content of its own that
@@ -916,6 +1047,326 @@ wxXmlResource::DoCreateResFromNode(wxXmlNode& node,
     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<wxIdRange*>::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<wxIdRange*>::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<wxXmlSubclassFactory*>
 {
@@ -952,23 +1403,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())
@@ -976,12 +1439,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
@@ -997,62 +1460,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); // deprecated
-    XRC_ADD_STYLE(wxBORDER_THEME);
-    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);
 
@@ -1065,10 +1494,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
         {
@@ -1084,19 +1513,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 )
@@ -1105,7 +1534,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;
@@ -1147,12 +1576,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
         {
@@ -1174,53 +1603,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);
 
     // 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;
-    if (!str.ToCDouble(&value))
-        value = defaultv;
+    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);
 
@@ -1277,7 +1724,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);
 
@@ -1292,7 +1739,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
@@ -1337,7 +1784,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)
 {
@@ -1358,7 +1805,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)
 {
@@ -1370,7 +1817,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;
     }
 
@@ -1394,7 +1841,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node,
     wxImage img(name);
 #endif
 
-    if (!img.Ok())
+    if (!img.IsOk())
     {
         ReportParamError
         (
@@ -1408,7 +1855,7 @@ wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node,
 }
 
 
-wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
+wxIcon wxXmlResourceHandlerImpl::GetIcon(const wxString& param,
                                      const wxArtClient& defaultArtClient,
                                      wxSize size)
 {
@@ -1426,7 +1873,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)
 {
@@ -1436,7 +1883,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;
@@ -1484,14 +1931,14 @@ 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;
 
     // Get the size if we have it, otherwise we will use the size of the first
     // list element.
@@ -1503,12 +1950,12 @@ wxImageList *wxXmlResourceHandler::GetImageList(const wxString& param)
     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);
+                wxIcon icon = GetIcon(n, wxART_OTHER, size);
                 if ( !imagelist )
                 {
                     // We need the real image list size to create it.
@@ -1528,15 +1975,15 @@ wxImageList *wxXmlResourceHandler::GetImageList(const wxString& param)
         }
     }
 
-    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)
     {
@@ -1555,15 +2002,14 @@ wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
     return NULL;
 }
 
-/* static */
-bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
+bool wxXmlResourceHandlerImpl::IsOfClass(wxXmlNode *node, const wxString& classname) const
 {
     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;
@@ -1581,21 +2027,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);
@@ -1623,9 +2069,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
         {
@@ -1643,7 +2089,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);
@@ -1651,7 +2097,7 @@ wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
 
 
 
-wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
+wxCoord wxXmlResourceHandlerImpl::GetDimension(const wxString& param,
                                            wxCoord defaultv,
                                            wxWindow *windowToUse)
 {
@@ -1679,9 +2125,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
         {
@@ -1697,6 +2143,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)
@@ -1718,7 +2198,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)
@@ -1728,8 +2208,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:
 
@@ -1749,6 +2229,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
@@ -1761,6 +2249,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
@@ -1779,6 +2275,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)
+            );
+        }
     }
 
 
@@ -1821,13 +2325,50 @@ wxFont wxXmlResourceHandler::GetFont(const wxString& param)
     }
 #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"))));
@@ -1852,12 +2393,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
 
@@ -1885,36 +2426,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->DoCreateResFromNode(*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);
         }
@@ -1927,21 +2468,21 @@ 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(const wxXmlNode *context, const wxString& message)
@@ -1996,13 +2537,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)
 {
-    unsigned int index = 0;
+    unsigned index = 0;
 
     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)
     {
@@ -2069,11 +2645,14 @@ 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);
@@ -2086,6 +2665,7 @@ 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);
@@ -2094,6 +2674,8 @@ void AddStdXRCID_Records()
     stdID(wxID_VIEW_SORTNAME);
     stdID(wxID_VIEW_SORTSIZE);
     stdID(wxID_VIEW_SORTTYPE);
+
+
     stdID(wxID_FILE1);
     stdID(wxID_FILE2);
     stdID(wxID_FILE3);
@@ -2103,6 +2685,8 @@ void AddStdXRCID_Records()
     stdID(wxID_FILE7);
     stdID(wxID_FILE8);
     stdID(wxID_FILE9);
+
+
     stdID(wxID_OK);
     stdID(wxID_CANCEL);
     stdID(wxID_APPLY);
@@ -2123,12 +2707,14 @@ 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);
@@ -2144,13 +2730,6 @@ 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);
@@ -2170,6 +2749,23 @@ 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
 }
 
@@ -2254,6 +2850,7 @@ public:
     void OnExit()
     {
         delete wxXmlResource::Set(NULL);
+        delete wxIdRangeManager::Set(NULL);
         if(wxXmlResource::ms_subclassFactories)
         {
             for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();