#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"
// this is a class so that it can be forward-declared
};
+namespace
+{
+
+// helper used by DoFindResource() and elsewhere: returns true if this is an
+// object or object_ref node
+//
+// node must be non-NULL
+inline bool IsObjectNode(wxXmlNode *node)
+{
+ return node->GetType() == wxXML_ELEMENT_NODE &&
+ (node->GetName() == wxS("object") ||
+ node->GetName() == wxS("object_ref"));
+}
+
+// special XML attribute with name of input file, see GetFileNameFromNode()
+const char *ATTR_INPUT_FILENAME = "__wx:filename";
+
+// helper to get filename corresponding to an XML node
+wxString
+GetFileNameFromNode(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'
+ // is in
+ for ( ;; )
+ {
+ // in some rare cases (specifically, when an <object_ref> is used, see
+ // wxXmlResource::CreateResFromNode() and MergeNodesOver()), we work
+ // with XML nodes that are not rooted in any document from 'files'
+ // (because a new node was created by CreateResFromNode() to merge the
+ // content of <object_ref> and the referenced <object>); in that case,
+ // we hack around the problem by putting the information about input
+ // file into a custom attribute
+ if ( node->HasAttribute(ATTR_INPUT_FILENAME) )
+ return node->GetAttribute(ATTR_INPUT_FILENAME);
+
+ if ( !node->GetParent() )
+ break; // we found the root of this XML tree
+
+ node = node->GetParent();
+ }
+
+ // NB: 'node' now points to the root of XML document
+
+ for ( wxXmlResourceDataRecords::const_iterator i = files.begin();
+ i != files.end(); ++i )
+ {
+ if ( (*i)->Doc->GetRoot() == node )
+ {
+ return (*i)->File;
+ }
+ }
+
+ return wxEmptyString; // not found
+}
+
+} // anonymous namespace
+
wxXmlResource *wxXmlResource::ms_instance = NULL;
#endif // wxUSE_FILESYSTEM
-bool wxXmlResource::Load(const wxString& filemask)
+bool wxXmlResource::LoadFile(const wxFileName& file)
+{
+#if wxUSE_FILESYSTEM
+ return Load(wxFileSystem::FileNameToURL(file));
+#else
+ return Load(file.GetFullPath());
+#endif
+}
+
+bool wxXmlResource::LoadAllFiles(const wxString& dirname)
+{
+ bool ok = true;
+ wxArrayString files;
+
+ wxDir::GetAllFiles(dirname, &files, "*.xrc");
+
+ for ( wxArrayString::const_iterator i = files.begin(); i != files.end(); ++i )
+ {
+ if ( !LoadFile(*i) )
+ ok = false;
+ }
+
+ return ok;
+}
+
+bool wxXmlResource::Load(const wxString& filemask_)
{
+ wxString filemask = ConvertFileNameToURL(filemask_);
+
#if wxUSE_FILESYSTEM
wxFileSystem fsys;
# define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE)
while (!fnd.empty())
{
- fnd = ConvertFileNameToURL(fnd);
-
#if wxUSE_FILESYSTEM
if ( IsArchive(fnd) )
{
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;
}
wxWindow *container = parent->FindWindow(name + wxT("_container"));
if (!container)
{
- wxLogError(_("Cannot find container for unknown control '%s'."), name.c_str());
+ wxLogError("Cannot find container for unknown control '%s'.", name);
return false;
}
return control->Reparent(container);
if (modif)
{
- wxLogTrace(_T("xrc"), _T("opening file '%s'"), rec->File);
+ wxLogTrace(wxT("xrc"), wxT("opening file '%s'"), rec->File);
wxInputStream *stream = NULL;
delete rec->Doc;
rec->Doc = new wxXmlDocument;
}
- if (!stream || !rec->Doc->Load(*stream, encoding))
+ if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding))
{
wxLogError(_("Cannot load resources from file '%s'."),
rec->File);
}
else if (rec->Doc->GetRoot()->GetName() != wxT("resource"))
{
- wxLogError(_("Invalid XRC resource '%s': doesn't have root node 'resource'."), rec->File);
+ ReportError
+ (
+ rec->Doc->GetRoot(),
+ "invalid XRC resource, doesn't have root node <resource>"
+ );
wxDELETE(rec->Doc);
rt = false;
}
m_version = version;
if (m_version != version)
{
- wxLogError(_("Resource files must have same version number!"));
+ wxLogError("Resource files must have same version number.");
rt = false;
}
return rt;
}
-
wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,
const wxString& name,
const wxString& classname,
- bool recursive)
+ bool recursive) const
{
- wxString dummy;
wxXmlNode *node;
// first search for match at the top-level nodes (as this is
// where the resource is most commonly looked for):
for (node = parent->GetChildren(); node; node = node->GetNext())
{
- if ( node->GetType() == wxXML_ELEMENT_NODE &&
- (node->GetName() == wxT("object") ||
- node->GetName() == wxT("object_ref")) &&
- node->GetAttribute(wxT("name"), &dummy) && dummy == name )
+ if ( IsObjectNode(node) && node->GetAttribute(wxS("name")) == name )
{
- wxString cls(node->GetAttribute(wxT("class"), wxEmptyString));
- if (!classname || cls == classname)
+ // empty class name matches everything
+ if ( classname.empty() )
return node;
+
+ wxString cls(node->GetAttribute(wxS("class")));
+
// object_ref may not have 'class' attribute:
- if (cls.empty() && node->GetName() == wxT("object_ref"))
+ if (cls.empty() && node->GetName() == wxS("object_ref"))
{
- wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString);
+ wxString refName = node->GetAttribute(wxS("ref"));
if (refName.empty())
continue;
- wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
- if (refNode &&
- refNode->GetAttribute(wxT("class"), wxEmptyString) == classname)
- {
- return node;
- }
+
+ const wxXmlNode * const refNode = GetResourceNode(refName);
+ if ( refNode )
+ cls = refNode->GetAttribute(wxS("class"));
}
+
+ if ( cls == classname )
+ return node;
}
}
+ // then recurse in child nodes
if ( recursive )
+ {
for (node = parent->GetChildren(); node; node = node->GetNext())
{
- if ( node->GetType() == wxXML_ELEMENT_NODE &&
- (node->GetName() == wxT("object") ||
- node->GetName() == wxT("object_ref")) )
+ if ( IsObjectNode(node) )
{
wxXmlNode* found = DoFindResource(node, name, classname, true);
if ( found )
return found;
}
}
+ }
- return NULL;
+ return NULL;
}
wxXmlNode *wxXmlResource::FindResource(const wxString& name,
const wxString& classname,
bool recursive)
{
- UpdateResources(); //ensure everything is up-to-date
+ wxString path;
+ wxXmlNode * const
+ node = GetResourceNodeAndLocation(name, classname, recursive, &path);
+
+ if ( !node )
+ {
+ ReportError
+ (
+ NULL,
+ wxString::Format
+ (
+ "XRC resource \"%s\" (class \"%s\") not found",
+ name, classname
+ )
+ );
+ }
+#if wxUSE_FILESYSTEM
+ else // node was found
+ {
+ // ensure that relative paths work correctly when loading this node
+ // (which should happen as soon as we return as FindResource() result
+ // is always passed to CreateResFromNode())
+ m_curFileSystem.ChangePathTo(path);
+ }
+#endif // wxUSE_FILESYSTEM
+
+ return node;
+}
+
+wxXmlNode *
+wxXmlResource::GetResourceNodeAndLocation(const wxString& name,
+ const wxString& classname,
+ bool recursive,
+ wxString *path) const
+{
+ // ensure everything is up-to-date: this is needed to support on-remand
+ // reloading of XRC files
+ const_cast<wxXmlResource *>(this)->UpdateResources();
- wxString dummy;
for ( wxXmlResourceDataRecords::const_iterator f = Data().begin();
f != Data().end(); ++f )
{
- wxXmlResourceDataRecord* const rec = *f;
- if ( rec->Doc == NULL || rec->Doc->GetRoot() == NULL )
+ wxXmlResourceDataRecord *const rec = *f;
+ wxXmlDocument * const doc = rec->Doc;
+ if ( !doc || !doc->GetRoot() )
continue;
- wxXmlNode* found = DoFindResource(rec->Doc->GetRoot(),
- name, classname, recursive);
+ wxXmlNode * const
+ found = DoFindResource(doc->GetRoot(), name, classname, recursive);
if ( found )
{
-#if wxUSE_FILESYSTEM
- m_curFileSystem.ChangePathTo(rec->File);
-#endif
+ if ( path )
+ *path = rec->File;
+
return found;
}
}
- wxLogError(_("XRC resource '%s' (class '%s') not found!"),
- name.c_str(), classname.c_str());
return NULL;
}
-static void MergeNodes(wxXmlNode& dest, wxXmlNode& with)
+static void MergeNodesOver(wxXmlNode& dest, wxXmlNode& overwriteWith,
+ const wxString& overwriteFilename)
{
// Merge attributes:
- for ( wxXmlAttribute *attr = with.GetAttributes();
+ for ( wxXmlAttribute *attr = overwriteWith.GetAttributes();
attr; attr = attr->GetNext() )
{
wxXmlAttribute *dattr;
}
// Merge child nodes:
- for (wxXmlNode* node = with.GetChildren(); node; node = node->GetNext())
+ for (wxXmlNode* node = overwriteWith.GetChildren(); node; node = node->GetNext())
{
wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
wxXmlNode *dnode;
dnode->GetAttribute(wxT("name"), wxEmptyString) == name &&
dnode->GetType() == node->GetType() )
{
- MergeNodes(*dnode, *node);
+ MergeNodesOver(*dnode, *node, overwriteFilename);
break;
}
}
if ( !dnode )
{
+ wxXmlNode *copyOfNode = new wxXmlNode(*node);
+ // remember referenced object's file, see GetFileNameFromNode()
+ copyOfNode->AddAttribute(ATTR_INPUT_FILENAME, overwriteFilename);
+
static const wxChar *AT_END = wxT("end");
wxString insert_pos = node->GetAttribute(wxT("insert_at"), AT_END);
if ( insert_pos == AT_END )
{
- dest.AddChild(new wxXmlNode(*node));
+ dest.AddChild(copyOfNode);
}
else if ( insert_pos == wxT("begin") )
{
- dest.InsertChild(new wxXmlNode(*node), dest.GetChildren());
+ dest.InsertChild(copyOfNode, dest.GetChildren());
}
}
}
- if ( dest.GetType() == wxXML_TEXT_NODE && with.GetContent().length() )
- dest.SetContent(with.GetContent());
+ if ( dest.GetType() == wxXML_TEXT_NODE && overwriteWith.GetContent().length() )
+ 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 )
{
- wxLogError(_("Referenced object node with ref=\"%s\" not found!"),
- refName.c_str());
+ ReportError
+ (
+ &node,
+ wxString::Format
+ (
+ "referenced object node with ref=\"%s\" not found",
+ refName
+ )
+ );
return NULL;
}
- wxXmlNode copy(*refNode);
- MergeNodes(copy, *node);
+ 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.
- return CreateResFromNode(©, parent, instance);
+ 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 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);
}
}
- wxLogError(_("No handler found for XML node '%s', class '%s'!"),
- node->GetName().c_str(),
- node->GetAttribute(wxT("class"), wxEmptyString).c_str());
+ ReportError
+ (
+ &node,
+ wxString::Format
+ (
+ "no handler found for XML node \"%s\" (class \"%s\")",
+ node.GetName(),
+ node.GetAttribute("class", wxEmptyString)
+ )
+ );
return NULL;
}
if (!m_instance)
{
wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
- wxLogError(_("Subclass '%s' not found for resource '%s', not subclassing!"),
- subclass.c_str(), name.c_str());
+ ReportError
+ (
+ node,
+ wxString::Format
+ (
+ "subclass \"%s\" not found for resource \"%s\", not subclassing",
+ subclass, name
+ )
+ );
}
}
}
// 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);
fl = tkn.GetNextToken();
index = m_styleNames.Index(fl);
if (index != wxNOT_FOUND)
+ {
style |= m_styleValues[index];
+ }
else
- wxLogError(_("Unknown style flag ") + fl);
+ {
+ ReportParamError
+ (
+ param,
+ wxString::Format("unknown style flag \"%s\"", fl)
+ );
+ }
}
return style;
}
{
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)
if (clr.Ok())
return clr;
- wxLogError(_("XRC resource: Incorrect colour specification '%s' for attribute '%s'."),
- v.c_str(), param.c_str());
+ ReportParamError
+ (
+ param,
+ wxString::Format("incorrect colour specification \"%s\"", v)
+ );
return wxNullColour;
}
return clr;
}
+namespace
+{
+
+// if 'param' has stock_id/stock_client, extracts them and returns true
+bool GetStockArtAttrs(const wxXmlNode *paramNode,
+ const wxString& defaultArtClient,
+ wxString& art_id, wxString& art_client)
+{
+ if ( paramNode )
+ {
+ art_id = paramNode->GetAttribute("stock_id", "");
+
+ if ( !art_id.empty() )
+ {
+ art_id = wxART_MAKE_ART_ID_FROM_STR(art_id);
+
+ art_client = paramNode->GetAttribute("stock_client", "");
+ if ( art_client.empty() )
+ art_client = defaultArtClient;
+ else
+ art_client = wxART_MAKE_CLIENT_ID_FROM_STR(art_client);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // anonymous namespace
wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
const wxArtClient& defaultArtClient,
wxSize size)
{
- /* If the bitmap is specified as stock item, query wxArtProvider for it: */
- wxXmlNode *bmpNode = GetParamNode(param);
- if ( bmpNode )
+ // 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 )
{
- wxString sid = bmpNode->GetAttribute(wxT("stock_id"), wxEmptyString);
- if ( !sid.empty() )
- {
- wxString scl = bmpNode->GetAttribute(wxT("stock_client"), wxEmptyString);
- if (scl.empty())
- scl = defaultArtClient;
- else
- scl = wxART_MAKE_CLIENT_ID_FROM_STR(scl);
+ // this is not an error as bitmap parameter could be optional
+ return wxNullBitmap;
+ }
- wxBitmap stockArt =
- wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(sid),
- scl, size);
- if ( stockArt.Ok() )
- return stockArt;
- }
+ 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() )
+ return stockArt;
}
/* ...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);
if (fsfile == NULL)
{
- wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
- name.c_str());
+ ReportParamError
+ (
+ node->GetName(),
+ wxString::Format("cannot open bitmap resource \"%s\"", name)
+ );
return wxNullBitmap;
}
wxImage img(*(fsfile->GetStream()));
if (!img.Ok())
{
- wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
- name.c_str());
+ ReportParamError
+ (
+ node->GetName(),
+ wxString::Format("cannot create bitmap from \"%s\"", name)
+ );
return wxNullBitmap;
}
if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
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)
+{
+ wxString art_id, art_client;
+ if ( GetStockArtAttrs(GetParamNode(param), defaultArtClient,
+ art_id, art_client) )
+ {
+ wxIconBundle stockArt(wxArtProvider::GetIconBundle(art_id, art_client));
+ if ( stockArt.IsOk() )
+ return stockArt;
+ }
+
+ const wxString name = GetParamValue(param);
+ if ( name.empty() )
+ return wxNullIconBundle;
+
+#if wxUSE_FILESYSTEM
+ wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
+ if ( fsfile == NULL )
+ {
+ ReportParamError
+ (
+ param,
+ wxString::Format("cannot open icon resource \"%s\"", name)
+ );
+ return wxNullIconBundle;
+ }
+
+ wxIconBundle bundle(*(fsfile->GetStream()));
+ delete fsfile;
+#else
+ wxIconBundle bundle(name);
+#endif
+
+ if ( !bundle.IsOk() )
+ {
+ ReportParamError
+ (
+ param,
+ wxString::Format("cannot create icon from \"%s\"", name)
+ );
+ return wxNullIconBundle;
+ }
+
+ return bundle;
+}
+
+
+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;
+
+ // size
+ 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
+ wxString parambitmap = wxT("bitmap");
+ if ( HasParam(parambitmap) )
+ {
+ wxXmlNode *n = m_node->GetChildren();
+ while (n)
+ {
+ if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == parambitmap)
+ {
+ // add icon instead of bitmap to keep the bitmap mask
+ imagelist->Add(GetIcon(n));
+ }
+ n = n->GetNext();
+ }
+ }
+
+ m_node = oldnode;
+ return imagelist;
+}
wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
{
while (n)
{
if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
+ {
+ // TODO: check that there are no other properties/parameters with
+ // the same name and log an error if there are (can't do this
+ // right now as I'm not sure if it's not going to break code
+ // using this function in unintentional way (i.e. for
+ // accessing other things than properties), for example
+ // wxBitmapComboBoxXmlHandler almost surely does
return n;
+ }
n = n->GetNext();
}
return NULL;
}
-
-
bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
{
return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
-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 (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
!s.AfterLast(wxT(',')).ToLong(&sy))
{
- wxLogError(_("Cannot parse coordinates from '%s'."), s.c_str());
+ ReportParamError
+ (
+ param,
+ wxString::Format("cannot parse coordinates value \"%s\"", s)
+ );
return wxDefaultSize;
}
}
else
{
- wxLogError(_("Cannot convert dialog units: dialog unknown."));
+ ReportParamError
+ (
+ param,
+ "cannot convert dialog units: dialog unknown"
+ );
return wxDefaultSize;
}
}
if (!s.ToLong(&sx))
{
- wxLogError(_("Cannot parse dimension from '%s'."), s.c_str());
+ ReportParamError
+ (
+ param,
+ wxString::Format("cannot parse dimension value \"%s\"", s)
+ );
return defaultv;
}
}
else
{
- wxLogError(_("Cannot convert dialog units: dialog unknown."));
+ ReportParamError
+ (
+ param,
+ "cannot convert dialog units: dialog unknown"
+ );
return defaultv;
}
}
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)
SYSFNT(wxSYS_SYSTEM_FONT)
SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
- SYSFNT(wxSYS_DEFAULT_PALETTE)
SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
SYSFNT(wxSYS_DEFAULT_GUI_FONT)
#undef SYSFNT
wxXmlNode *font_node = GetParamNode(param);
if (font_node == NULL)
{
- wxLogError(_("Cannot find font node '%s'."), param.c_str());
+ ReportError(
+ wxString::Format("cannot find font node \"%s\"", param));
return wxNullFont;
}
// 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")));
}
void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
{
- wxXmlNode *n = m_node->GetChildren();
-
- while (n)
+ for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() )
{
- if (n->GetType() == wxXML_ELEMENT_NODE &&
- (n->GetName() == wxT("object") || n->GetName() == wxT("object_ref")))
+ if ( IsObjectNode(n) )
{
- m_resource->CreateResFromNode(n, parent, NULL,
- this_hnd_only ? this : NULL);
+ m_resource->DoCreateResFromNode(*n, parent, NULL,
+ this_hnd_only ? this : NULL);
}
- n = n->GetNext();
}
}
}
+//-----------------------------------------------------------------------------
+// errors reporting
+//-----------------------------------------------------------------------------
+
+void wxXmlResourceHandler::ReportError(const wxString& message)
+{
+ m_resource->ReportError(m_node, message);
+}
+
+void wxXmlResourceHandler::ReportError(wxXmlNode *context,
+ const wxString& message)
+{
+ m_resource->ReportError(context ? context : m_node, message);
+}
+
+void wxXmlResourceHandler::ReportParamError(const wxString& param,
+ const wxString& message)
+{
+ m_resource->ReportError(GetParamNode(param), message);
+}
+
+void wxXmlResource::ReportError(wxXmlNode *context, const wxString& message)
+{
+ if ( !context )
+ {
+ DoReportError("", NULL, message);
+ return;
+ }
+ // We need to find out the file that 'context' is part of. Performance of
+ // this code is not critical, so we simply find the root XML node and
+ // compare it with all loaded XRC files.
+ const wxString filename = GetFileNameFromNode(context, Data());
+ DoReportError(filename, context, message);
+}
+void wxXmlResource::DoReportError(const wxString& xrcFile, wxXmlNode *position,
+ const wxString& message)
+{
+ const int line = position ? position->GetLineNumber() : -1;
+ wxString loc;
+ if ( !xrcFile.empty() )
+ loc = xrcFile + ':';
+ if ( line != -1 )
+ loc += wxString::Format("%d:", line);
+ if ( !loc.empty() )
+ loc += ' ';
+
+ wxLogError("XRC error: %s%s", loc, message);
+}
-// --------------- XRCID implementation -----------------------------
+
+//-----------------------------------------------------------------------------
+// XRCID implementation
+//-----------------------------------------------------------------------------
#define XRCID_TABLE_SIZE 1024
static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE)
{
- int index = 0;
+ unsigned int 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;
XRCID_record *oldrec = NULL;
return (*rec_var)->id;
}
-static void AddStdXRCID_Records();
-
-/*static*/
-int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found)
+namespace
{
- static bool s_stdIDsAdded = false;
-
- if ( !s_stdIDsAdded )
- {
- s_stdIDsAdded = true;
- AddStdXRCID_Records();
- }
- return XRCID_Lookup(str_id, value_if_not_found);
-}
+// flag indicating whether standard XRC ids were already initialized
+static bool gs_stdIDsAdded = false;
-/* 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;
- }
-}
-
-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 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;
+}
-// --------------- module and globals -----------------------------
+//-----------------------------------------------------------------------------
+// module and globals
+//-----------------------------------------------------------------------------
// normally we would do the cleanup from wxXmlResourceModule::OnExit() but it
// can happen that some XRC records have been created because of the use of