#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;
#if wxUSE_DATETIME
wxDateTime Time;
#endif
+
+ wxDECLARE_NO_COPY_CLASS(wxXmlResourceDataRecord);
};
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
{
// 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'
{
wxString filemask = ConvertFileNameToURL(filemask_);
+ bool allOK = true;
+
#if wxUSE_FILESYSTEM
wxFileSystem fsys;
# define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE)
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;
# undef wxXmlFindFirst
# undef wxXmlFindNext
- return UpdateResources();
+ return allOK;
}
bool wxXmlResource::Unload(const wxString& filename)
{
wxASSERT_MSG( !wxIsWild(filename),
- _T("wildcards not supported by wxXmlResource::Unload()") );
+ wxT("wildcards not supported by wxXmlResource::Unload()") );
wxString fnd = ConvertFileNameToURL(filename);
#if wxUSE_FILESYSTEM
const bool isArchive = IsArchive(fnd);
if ( isArchive )
- fnd += _T("#zip:");
+ fnd += wxT("#zip:");
#endif // wxUSE_FILESYSTEM
bool unloaded = false;
}
-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;
}
}
}
+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(_T("xrc"), _T("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,
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();
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",
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
// 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
{
// 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"))
+ {
+ for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
+ h != m_handlers.end(); ++h )
+ {
+ wxXmlResourceHandler *handler = *h;
+ if (handler->CanHandle(&node))
+ return handler->CreateResource(&node, parent, instance);
}
}
- else if (node->GetName() == wxT("object"))
+
+ ReportError
+ (
+ &node,
+ wxString::Format
+ (
+ "no handler found for XML node \"%s\" (class \"%s\")",
+ 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<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 )
{
- for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
- h != m_handlers.end(); ++h )
+ // Check if this range has already been finalised. Quite possible,
+ // as FinaliseRanges() gets called for each .xrc file loaded
+ if (!(*i)->IsFinalised())
{
- wxXmlResourceHandler *handler = *h;
- if (handler->CanHandle(node))
- return handler->CreateResource(node, parent, instance);
+ wxLogTrace("xrcrange", "Finalising ID range %s", (*i)->GetName());
+ (*i)->Finalise(node);
}
}
-
- ReportError
- (
- node,
- wxString::Format
- (
- "no handler found for XML node \"%s\" (class \"%s\")",
- node->GetName(),
- node->GetAttribute("class", wxEmptyString)
- )
- );
- return NULL;
}
// 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(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(wxBORDER_DEFAULT);
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(wxVSCROLL);
+ XRC_ADD_STYLE(wxHSCROLL);
XRC_ADD_STYLE(wxALWAYS_SHOW_SB);
+
XRC_ADD_STYLE(wxWS_EX_BLOCK_EVENTS);
XRC_ADD_STYLE(wxWS_EX_VALIDATE_RECURSIVELY);
+ XRC_ADD_STYLE(wxWS_EX_TRANSIENT);
+ XRC_ADD_STYLE(wxWS_EX_CONTEXTHELP);
+ XRC_ADD_STYLE(wxWS_EX_PROCESS_IDLE);
+ XRC_ADD_STYLE(wxWS_EX_PROCESS_UI_UPDATES);
}
// 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;
long wxXmlResourceHandler::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;
}
{
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);
}
if (!name.empty())
{
#define SYSCLR(clr) \
- if (name == _T(#clr)) return wxSystemSettings::GetColour(clr);
+ if (name == wxT(#clr)) return wxSystemSettings::GetColour(clr);
SYSCLR(wxSYS_COLOUR_SCROLLBAR)
SYSCLR(wxSYS_COLOUR_BACKGROUND)
SYSCLR(wxSYS_COLOUR_DESKTOP)
// 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
const wxArtClient& defaultArtClient,
wxSize size)
{
- return GetBitmap(GetParamNode(param), defaultArtClient, size);
+ // it used to be possible to pass an empty string here to indicate that the
+ // bitmap name should be read from this node itself but this is not
+ // supported any more because GetBitmap(m_node) can be used directly
+ // instead
+ wxASSERT_MSG( !param.empty(), "bitmap parameter name can't be empty" );
+
+ const wxXmlNode* const node = GetParamNode(param);
+
+ if ( !node )
+ {
+ // this is not an error as bitmap parameter could be optional
+ return wxNullBitmap;
+ }
+
+ return GetBitmap(node, defaultArtClient, size);
}
wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node,
const wxArtClient& defaultArtClient,
wxSize size)
{
+ wxCHECK_MSG( node, wxNullBitmap, "bitmap node can't be NULL" );
+
/* If the bitmap is specified as stock item, query wxArtProvider for it: */
wxString art_id, art_client;
if ( GetStockArtAttrs(node, defaultArtClient,
art_id, art_client) )
{
wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size));
- if ( stockArt.Ok() )
+ if ( stockArt.IsOk() )
return stockArt;
}
wxImage img(name);
#endif
- if (!img.Ok())
+ if (!img.IsOk())
{
ReportParamError
(
const wxArtClient& defaultArtClient,
wxSize size)
{
- return GetIcon(GetParamNode(param), defaultArtClient, size);
+ // see comment in GetBitmap(wxString) overload
+ wxASSERT_MSG( !param.empty(), "icon parameter name can't be empty" );
+
+ const wxXmlNode* const node = GetParamNode(param);
+
+ if ( !node )
+ {
+ // this is not an error as icon parameter could be optional
+ return wxIcon();
+ }
+
+ return GetIcon(node, defaultArtClient, size);
}
wxIcon wxXmlResourceHandler::GetIcon(const wxXmlNode* node,
wxXmlNode * const oldnode = m_node;
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) )
{
{
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 = !HasParam(wxS("mask")) || GetBool(wxS("mask"));
+
+ 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();
}
return NULL;
}
+/* static */
bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
{
- return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
+ return node->GetAttribute(wxT("class")) == classname;
}
return sx;
}
+wxDirection
+wxXmlResourceHandler::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)
if (!name.empty())
{
#define SYSFNT(fnt) \
- if (name == _T(#fnt)) return wxSystemSettings::GetFont(fnt);
+ if (name == wxT(#fnt)) return wxSystemSettings::GetFont(fnt);
SYSFNT(wxSYS_OEM_FIXED_FONT)
SYSFNT(wxSYS_ANSI_FIXED_FONT)
SYSFNT(wxSYS_ANSI_VAR_FONT)
return wxNullFont;
}
-wxFont wxXmlResourceHandler::GetFont(const wxString& param)
+wxFont wxXmlResourceHandler::GetFont(const wxString& param, wxWindow* parent)
{
wxXmlNode *font_node = GetParamNode(param);
if (font_node == NULL)
istyle = wxITALIC;
else if (style == wxT("slant"))
istyle = wxSLANT;
+ else if (style != wxT("normal"))
+ {
+ ReportParamError
+ (
+ param,
+ wxString::Format("unknown font style \"%s\"", style)
+ );
+ }
}
// weight
iweight = wxBOLD;
else if (weight == wxT("light"))
iweight = wxLIGHT;
+ else if (weight != wxT("normal"))
+ {
+ ReportParamError
+ (
+ param,
+ wxString::Format("unknown font weight \"%s\"", weight)
+ );
+ }
}
// underline
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)
+ );
+ }
}
// encoding
wxFontEncoding enc = wxFONTENCODING_DEFAULT;
bool hasEncoding = HasParam(wxT("encoding"));
+#if wxUSE_FONTMAP
if (hasEncoding)
{
wxString encoding = GetParamValue(wxT("encoding"));
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"))));
wnd->SetExtraStyle(wnd->GetExtraStyle() | GetStyle(wxT("exstyle")));
if (HasParam(wxT("bg")))
wnd->SetBackgroundColour(GetColour(wxT("bg")));
+ if (HasParam(wxT("ownbg")))
+ wnd->SetOwnBackgroundColour(GetColour(wxT("ownbg")));
if (HasParam(wxT("fg")))
wnd->SetForegroundColour(GetColour(wxT("fg")));
+ if (HasParam(wxT("ownfg")))
+ wnd->SetOwnForegroundColour(GetColour(wxT("ownfg")));
if (GetBool(wxT("enabled"), 1) == 0)
wnd->Enable(false);
if (GetBool(wxT("focused"), 0) == 1)
wnd->SetToolTip(GetText(wxT("tooltip")));
#endif
if (HasParam(wxT("font")))
- wnd->SetFont(GetFont());
+ wnd->SetFont(GetFont(wxT("font"), wnd));
+ if (HasParam(wxT("ownfont")))
+ wnd->SetOwnFont(GetFont(wxT("ownfont"), wnd));
if (HasParam(wxT("help")))
wnd->SetHelpText(GetText(wxT("help")));
}
{
if ( IsObjectNode(n) )
{
- m_resource->CreateResFromNode(n, parent, NULL,
- this_hnd_only ? this : NULL);
+ m_resource->DoCreateResFromNode(*n, parent, NULL,
+ this_hnd_only ? this : NULL);
}
}
}
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 )
{
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;
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)
{
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);
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);
stdID(wxID_REPLACE);
stdID(wxID_REPLACE_ALL);
stdID(wxID_PROPERTIES);
+
stdID(wxID_VIEW_DETAILS);
stdID(wxID_VIEW_LARGEICONS);
stdID(wxID_VIEW_SMALLICONS);
stdID(wxID_VIEW_SORTNAME);
stdID(wxID_VIEW_SORTSIZE);
stdID(wxID_VIEW_SORTTYPE);
+
+
stdID(wxID_FILE1);
stdID(wxID_FILE2);
stdID(wxID_FILE3);
stdID(wxID_FILE7);
stdID(wxID_FILE8);
stdID(wxID_FILE9);
+
+
stdID(wxID_OK);
stdID(wxID_CANCEL);
stdID(wxID_APPLY);
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);
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);
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;
+}
//-----------------------------------------------------------------------------
void OnExit()
{
delete wxXmlResource::Set(NULL);
+ delete wxIdRangeManager::Set(NULL);
if(wxXmlResource::ms_subclassFactories)
{
for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();