#include "wx/fontenum.h"
#include "wx/fontmap.h"
#include "wx/artprov.h"
+#include "wx/imaglist.h"
#include "wx/dir.h"
#include "wx/xml/xml.h"
+#include "wx/hashset.h"
class wxXmlResourceDataRecord
// this is a class so that it can be forward-declared
};
+WX_DECLARE_HASH_SET(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;
+ // Removes, if it exists, an entry from the XRCID table. Used in id-ranges
+ // to replace defunct or statically-initialised entries with current values
+ static void RemoveXRCIDEntry(const wxString& idstr);
+
+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'
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()
{
if (modif)
{
- wxLogTrace(_T("xrc"), _T("opening file '%s'"), rec->File);
+ wxLogTrace(wxT("xrc"), wxT("opening file '%s'"), rec->File);
wxInputStream *stream = NULL;
}
ProcessPlatformProperty(rec->Doc->GetRoot());
+ PreprocessForIdRanges(rec->Doc->GetRoot());
+ wxIdRangeManager::Get()->FinaliseRanges(rec->Doc->GetRoot());
#if wxUSE_DATETIME
#if wxUSE_FILESYSTEM
rec->Time = file->GetModificationTime();
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;
}
- wxXmlNode copy(*refNode);
- MergeNodesOver(copy, *node, GetFileNameFromNode(node, Data()));
+ if ( !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.
- // remember referenced object's file, see GetFileNameFromNode()
- copy.AddAttribute(ATTR_INPUT_FILENAME,
- GetFileNameFromNode(refNode, Data()));
+ return DoCreateResFromNode(*refNode, parent, instance);
+ }
+ else
+ {
+ // In the more complicated (but rare) case, <object_ref> has
+ // subnodes that partially overwrite content of the referenced
+ // object. In this case, we need to merge both XML trees and
+ // load the resource from result of the merge.
+
+ wxXmlNode copy(*refNode);
+ MergeNodesOver(copy, node, GetFileNameFromNode(&node, Data()));
+
+ // remember referenced object's file, see GetFileNameFromNode()
+ copy.AddAttribute(ATTR_INPUT_FILENAME,
+ GetFileNameFromNode(refNode, Data()));
- return CreateResFromNode(©, parent, instance);
+ return DoCreateResFromNode(copy, parent, instance);
+ }
}
if (handlerToUse)
{
- if (handlerToUse->CanHandle(node))
+ if (handlerToUse->CanHandle(&node))
{
- return handlerToUse->CreateResource(node, parent, instance);
+ return handlerToUse->CreateResource(&node, parent, instance);
}
}
- else if (node->GetName() == wxT("object"))
+ else if (node.GetName() == wxT("object"))
{
for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
h != m_handlers.end(); ++h )
{
wxXmlResourceHandler *handler = *h;
- if (handler->CanHandle(node))
- return handler->CreateResource(node, parent, instance);
+ if (handler->CanHandle(&node))
+ return handler->CreateResource(&node, parent, instance);
}
}
ReportError
(
- node,
+ &node,
wxString::Format
(
"no handler found for XML node \"%s\" (class \"%s\")",
- node->GetName(),
- node->GetAttribute("class", wxEmptyString)
+ node.GetName(),
+ node.GetAttribute("class", wxEmptyString)
)
);
return NULL;
}
+wxIdRange::wxIdRange(const wxXmlNode* node,
+ const wxString& rname,
+ const wxString& startno,
+ const wxString& rsize)
+ : m_name(rname),
+ m_start(0),
+ m_size(0),
+ m_item_end_found(0),
+ m_finalised(0)
+{
+ long l;
+ if ( startno.ToLong(&l) )
+ {
+ if ( l >= 0 )
+ {
+ m_start = l;
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "a negative id-range start parameter was given"
+ );
+ }
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "the id-range start parameter was malformed"
+ );
+ }
+
+ unsigned long ul;
+ if ( rsize.ToULong(&ul) )
+ {
+ m_size = ul;
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "the id-range size parameter was malformed"
+ );
+ }
+}
+
+void wxIdRange::NoteItem(const wxXmlNode* node, const wxString& item)
+{
+ // Nothing gets added here, but the existence of each item is noted
+ // thus getting an accurate count. 'item' will be either an integer e.g.
+ // [0] [123]: will eventually create an XRCID as start+integer or [start]
+ // or [end] which are synonyms for [0] or [range_size-1] respectively.
+ wxString content(item.Mid(1, item.length()-2));
+
+ // Check that basename+item wasn't foo[]
+ if (content.empty())
+ {
+ wxXmlResource::Get()->ReportError(node, "an empty id-range item found");
+ return;
+ }
+
+ if (content=="start")
+ {
+ // "start" means [0], so store that in the set
+ if (m_indices.count(0) == 0)
+ {
+ m_indices.insert(0);
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "duplicate id-range item found"
+ );
+ }
+ }
+ else if (content=="end")
+ {
+ // We can't yet be certain which XRCID this will be equivalent to, so
+ // just note that there's an item with this name, in case we need to
+ // inc the range size
+ m_item_end_found = true;
+ }
+ else
+ {
+ // Anything else will be an integer, or rubbish
+ unsigned long l;
+ if ( content.ToULong(&l) )
+ {
+ if (m_indices.count(l) == 0)
+ {
+ m_indices.insert(l);
+ // Check that this item wouldn't fall outside the current range
+ // extent
+ if (l >= m_size)
+ {
+ m_size = l + 1;
+ }
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "duplicate id-range item found"
+ );
+ }
+
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "an id-range item had a malformed index"
+ );
+ }
+ }
+}
+
+void wxIdRange::Finalise(const wxXmlNode* node)
+{
+ wxCHECK_RET( !IsFinalised(),
+ "Trying to finalise an already-finalised range" );
+
+ // Now we know about all the items, we can get an accurate range size
+ // Expand any requested range-size if there were more items than would fit
+ m_size = wxMax(m_size, m_indices.size());
+
+ // If an item is explicitly called foo[end], ensure it won't clash with
+ // another item
+ if ( m_item_end_found && m_indices.count(m_size-1) )
+ ++m_size;
+ if (m_size == 0)
+ {
+ // This will happen if someone creates a range but no items in this xrc
+ // file Report the error and abort, but don't finalise, in case items
+ // appear later
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "trying to create an empty id-range"
+ );
+ return;
+ }
+
+ if (m_start==0)
+ {
+ // This is the usual case, where the user didn't specify a start ID
+ // So get the range using NewControlId().
+ //
+ // NB: negative numbers, but NewControlId already returns the most
+ // negative
+ m_start = wxWindow::NewControlId(m_size);
+ wxCHECK_RET( m_start != wxID_NONE,
+ "insufficient IDs available to create range" );
+ m_end = m_start + m_size - 1;
+ }
+ else
+ {
+ // The user already specified a start value, which must be positive
+ m_end = m_start + m_size - 1;
+ }
+
+ // Create the XRCIDs
+ for (int i=m_start; i <= m_end; ++i)
+ {
+ // First clear any pre-existing XRCID
+ // Necessary for wxXmlResource::Unload() followed by Load()
+ wxIdRangeManager::RemoveXRCIDEntry(
+ m_name + wxString::Format("[%i]", i-m_start));
+
+ // Use the second parameter of GetXRCID to force it to take the value i
+ wxXmlResource::GetXRCID(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
+ wxIdRangeManager::RemoveXRCIDEntry(m_name + "[start]");
+ wxXmlResource::GetXRCID(m_name + "[start]", m_start);
+ wxIdRangeManager::RemoveXRCIDEntry(m_name + "[end]");
+ wxXmlResource::GetXRCID(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*>
{
// 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);
{
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
-
+ // 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.ToDouble(&value))
+ if (!str.ToCDouble(&value))
value = defaultv;
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)
const wxArtClient& defaultArtClient,
wxSize 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(GetParamNode(param), defaultArtClient,
+ if ( GetStockArtAttrs(node, defaultArtClient,
art_id, art_client) )
{
wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size));
}
/* ...or load the bitmap from file: */
- wxString name = GetParamValue(param);
+ wxString name = GetParamValue(node);
if (name.empty()) return wxNullBitmap;
#if wxUSE_FILESYSTEM
wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
{
ReportParamError
(
- param,
+ node->GetName(),
wxString::Format("cannot open bitmap resource \"%s\"", name)
);
return wxNullBitmap;
{
ReportParamError
(
- param,
+ node->GetName(),
wxString::Format("cannot create bitmap from \"%s\"", name)
);
return wxNullBitmap;
wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
const wxArtClient& defaultArtClient,
wxSize size)
+{
+ // see comment in GetBitmap(wxString) overload
+ wxASSERT_MSG( !param.empty(), "icon parameter name can't be empty" );
+
+ const wxXmlNode* const node = GetParamNode(param);
+
+ if ( !node )
+ {
+ // this is not an error as icon parameter could be optional
+ return wxIcon();
+ }
+
+ return GetIcon(node, defaultArtClient, size);
+}
+
+wxIcon wxXmlResourceHandler::GetIcon(const wxXmlNode* node,
+ const wxArtClient& defaultArtClient,
+ wxSize size)
{
wxIcon icon;
- icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size));
+ icon.CopyFromBitmap(GetBitmap(node, defaultArtClient, size));
return icon;
}
+
wxIconBundle wxXmlResourceHandler::GetIconBundle(const wxString& param,
const wxArtClient& defaultArtClient)
{
}
+wxImageList *wxXmlResourceHandler::GetImageList(const wxString& param)
+{
+ wxXmlNode * const imagelist_node = GetParamNode(param);
+ if ( !imagelist_node )
+ return NULL;
+
+ wxXmlNode * const oldnode = m_node;
+ m_node = imagelist_node;
+
+ // Get the size if we have it, otherwise we will use the size of the first
+ // list element.
+ wxSize size = GetSize();
+
+ // Start adding images, we'll create the image list when adding the first
+ // one.
+ wxImageList * imagelist = NULL;
+ wxString parambitmap = wxT("bitmap");
+ if ( HasParam(parambitmap) )
+ {
+ wxXmlNode *n = m_node->GetChildren();
+ while (n)
+ {
+ if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == parambitmap)
+ {
+ wxIcon icon = GetIcon(n);
+ 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(icon);
+ }
+ n = n->GetNext();
+ }
+ }
+
+ m_node = oldnode;
+ return imagelist;
+}
+
wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
{
wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!"));
return NULL;
}
+/* static */
bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
{
- return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
+ return node->GetAttribute(wxT("class")) == classname;
}
-wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
+wxString wxXmlResourceHandler::GetNodeContent(const wxXmlNode *node)
{
- wxXmlNode *n = node;
+ const wxXmlNode *n = node;
if (n == NULL) return wxEmptyString;
n = n->GetChildren();
return GetNodeContent(GetParamNode(param));
}
+wxString wxXmlResourceHandler::GetParamValue(const wxXmlNode* node)
+{
+ return GetNodeContent(node);
+}
wxSize wxXmlResourceHandler::GetSize(const wxString& param,
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)
// 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
// is this font based on a system font?
wxFont font = GetSystemFont(GetParamValue(wxT("sysfont")));
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")));
+ if (HasParam(wxT("ownfont")))
+ wnd->SetOwnFont(GetFont(wxT("ownfont")));
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 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;
- }
-}
+// flag indicating whether standard XRC ids were already initialized
+static bool gs_stdIDsAdded = false;
-static void CleanXRCID_Records()
-{
- for (int i = 0; i < XRCID_TABLE_SIZE; i++)
- {
- CleanXRCID_Record(XRCID_Records[i]);
- XRCID_Records[i] = NULL;
- }
-}
-
-static void AddStdXRCID_Records()
+void AddStdXRCID_Records()
{
#define stdID(id) XRCID_Lookup(#id, id)
stdID(-1);
#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 wxIdRangeManager::RemoveXRCIDEntry(const wxString& idstr)
+{
+ const char *str_id = idstr.mb_str();
+ const unsigned index = XRCIdHash(str_id);
+ XRCID_record **p_previousrec = &XRCID_Records[index];
+ for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
+ {
+ if (wxStrcmp(rec->key, str_id) == 0)
+ {
+ // Found the item to be removed so delete its record; but first
+ // remove it from the linked list.
+ *p_previousrec = rec->next;
+ free(rec->key);
+ delete rec;
+ return;
+ }
+
+ p_previousrec = &rec->next;
+ }
+}
+
+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();