git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@48639 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1810 lines
48 KiB
C++
1810 lines
48 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/xrc/xmlres.cpp
|
|
// Purpose: XRC resources
|
|
// Author: Vaclav Slavik
|
|
// Created: 2000/03/05
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 2000 Vaclav Slavik
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_XRC
|
|
|
|
#include "wx/xrc/xmlres.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/intl.h"
|
|
#include "wx/log.h"
|
|
#include "wx/panel.h"
|
|
#include "wx/frame.h"
|
|
#include "wx/dialog.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/bitmap.h"
|
|
#include "wx/image.h"
|
|
#include "wx/module.h"
|
|
#include "wx/wxcrtvararg.h"
|
|
#endif
|
|
|
|
#ifndef __WXWINCE__
|
|
#include <locale.h>
|
|
#endif
|
|
|
|
#include "wx/vector.h"
|
|
#include "wx/wfstream.h"
|
|
#include "wx/filesys.h"
|
|
#include "wx/filename.h"
|
|
#include "wx/tokenzr.h"
|
|
#include "wx/fontenum.h"
|
|
#include "wx/fontmap.h"
|
|
#include "wx/artprov.h"
|
|
|
|
#include "wx/xml/xml.h"
|
|
|
|
class wxXmlResourceDataRecord
|
|
{
|
|
public:
|
|
wxXmlResourceDataRecord() : Doc(NULL) {
|
|
#if wxUSE_DATETIME
|
|
Time = wxDateTime::Now();
|
|
#endif
|
|
}
|
|
~wxXmlResourceDataRecord() {delete Doc;}
|
|
|
|
wxString File;
|
|
wxXmlDocument *Doc;
|
|
#if wxUSE_DATETIME
|
|
wxDateTime Time;
|
|
#endif
|
|
};
|
|
|
|
class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord>
|
|
{
|
|
// this is a class so that it can be forward-declared
|
|
};
|
|
|
|
|
|
wxXmlResource *wxXmlResource::ms_instance = NULL;
|
|
|
|
/*static*/ wxXmlResource *wxXmlResource::Get()
|
|
{
|
|
if ( !ms_instance )
|
|
ms_instance = new wxXmlResource;
|
|
return ms_instance;
|
|
}
|
|
|
|
/*static*/ wxXmlResource *wxXmlResource::Set(wxXmlResource *res)
|
|
{
|
|
wxXmlResource *old = ms_instance;
|
|
ms_instance = res;
|
|
return old;
|
|
}
|
|
|
|
wxXmlResource::wxXmlResource(int flags, const wxString& domain)
|
|
{
|
|
m_flags = flags;
|
|
m_version = -1;
|
|
m_data = new wxXmlResourceDataRecords;
|
|
SetDomain(domain);
|
|
}
|
|
|
|
wxXmlResource::wxXmlResource(const wxString& filemask, int flags, const wxString& domain)
|
|
{
|
|
m_flags = flags;
|
|
m_version = -1;
|
|
m_data = new wxXmlResourceDataRecords;
|
|
SetDomain(domain);
|
|
Load(filemask);
|
|
}
|
|
|
|
wxXmlResource::~wxXmlResource()
|
|
{
|
|
ClearHandlers();
|
|
|
|
delete m_data;
|
|
}
|
|
|
|
void wxXmlResource::SetDomain(const wxString& domain)
|
|
{
|
|
m_domain = domain;
|
|
}
|
|
|
|
|
|
/* static */
|
|
wxString wxXmlResource::ConvertFileNameToURL(const wxString& filename)
|
|
{
|
|
wxString fnd(filename);
|
|
|
|
// NB: as Load() and Unload() accept both filenames and URLs (should
|
|
// probably be changed to filenames only, but embedded resources
|
|
// currently rely on its ability to handle URLs - FIXME) we need to
|
|
// determine whether found name is filename and not URL and this is the
|
|
// fastest/simplest way to do it
|
|
if (wxFileName::FileExists(fnd))
|
|
{
|
|
// Make the name absolute filename, because the app may
|
|
// change working directory later:
|
|
wxFileName fn(fnd);
|
|
if (fn.IsRelative())
|
|
{
|
|
fn.MakeAbsolute();
|
|
fnd = fn.GetFullPath();
|
|
}
|
|
#if wxUSE_FILESYSTEM
|
|
fnd = wxFileSystem::FileNameToURL(fnd);
|
|
#endif
|
|
}
|
|
|
|
return fnd;
|
|
}
|
|
|
|
#if wxUSE_FILESYSTEM
|
|
|
|
/* static */
|
|
bool wxXmlResource::IsArchive(const wxString& filename)
|
|
{
|
|
const wxString fnd = filename.Lower();
|
|
|
|
return fnd.Matches(wxT("*.zip")) || fnd.Matches(wxT("*.xrs"));
|
|
}
|
|
|
|
#endif // wxUSE_FILESYSTEM
|
|
|
|
bool wxXmlResource::Load(const wxString& filemask)
|
|
{
|
|
wxString fnd;
|
|
bool iswild = wxIsWild(filemask);
|
|
bool rt = true;
|
|
|
|
#if wxUSE_FILESYSTEM
|
|
wxFileSystem fsys;
|
|
# define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE)
|
|
# define wxXmlFindNext fsys.FindNext()
|
|
#else
|
|
# define wxXmlFindFirst wxFindFirstFile(filemask, wxFILE)
|
|
# define wxXmlFindNext wxFindNextFile()
|
|
#endif
|
|
if (iswild)
|
|
fnd = wxXmlFindFirst;
|
|
else
|
|
fnd = filemask;
|
|
while (!fnd.empty())
|
|
{
|
|
fnd = ConvertFileNameToURL(fnd);
|
|
|
|
#if wxUSE_FILESYSTEM
|
|
if ( IsArchive(fnd) )
|
|
{
|
|
rt = rt && Load(fnd + wxT("#zip:*.xrc"));
|
|
}
|
|
else // a single resource URL
|
|
#endif // wxUSE_FILESYSTEM
|
|
{
|
|
wxXmlResourceDataRecord drec;
|
|
drec.File = fnd;
|
|
Data().push_back(drec);
|
|
}
|
|
|
|
if (iswild)
|
|
fnd = wxXmlFindNext;
|
|
else
|
|
fnd = wxEmptyString;
|
|
}
|
|
# undef wxXmlFindFirst
|
|
# undef wxXmlFindNext
|
|
return rt && UpdateResources();
|
|
}
|
|
|
|
bool wxXmlResource::Unload(const wxString& filename)
|
|
{
|
|
wxASSERT_MSG( !wxIsWild(filename),
|
|
_T("wildcards not supported by wxXmlResource::Unload()") );
|
|
|
|
wxString fnd = ConvertFileNameToURL(filename);
|
|
#if wxUSE_FILESYSTEM
|
|
const bool isArchive = IsArchive(fnd);
|
|
if ( isArchive )
|
|
fnd += _T("#zip:");
|
|
#endif // wxUSE_FILESYSTEM
|
|
|
|
bool unloaded = false;
|
|
for ( wxXmlResourceDataRecords::iterator i = Data().begin();
|
|
i != Data().end(); ++i )
|
|
{
|
|
#if wxUSE_FILESYSTEM
|
|
if ( isArchive )
|
|
{
|
|
if ( i->File.StartsWith(fnd) )
|
|
unloaded = true;
|
|
// don't break from the loop, we can have other matching files
|
|
}
|
|
else // a single resource URL
|
|
#endif // wxUSE_FILESYSTEM
|
|
{
|
|
if ( i->File == fnd )
|
|
{
|
|
Data().erase(i);
|
|
unloaded = true;
|
|
|
|
// no sense in continuing, there is only one file with this URL
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return unloaded;
|
|
}
|
|
|
|
|
|
IMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject)
|
|
|
|
void wxXmlResource::AddHandler(wxXmlResourceHandler *handler)
|
|
{
|
|
m_handlers.push_back(handler);
|
|
handler->SetParentResource(this);
|
|
}
|
|
|
|
void wxXmlResource::InsertHandler(wxXmlResourceHandler *handler)
|
|
{
|
|
m_handlers.insert(m_handlers.begin(), handler);
|
|
handler->SetParentResource(this);
|
|
}
|
|
|
|
|
|
|
|
void wxXmlResource::ClearHandlers()
|
|
{
|
|
for ( wxVector<wxXmlResourceHandler*>::iterator i = m_handlers.begin();
|
|
i != m_handlers.end(); ++i )
|
|
delete *i;
|
|
m_handlers.clear();
|
|
}
|
|
|
|
|
|
wxMenu *wxXmlResource::LoadMenu(const wxString& name)
|
|
{
|
|
return (wxMenu*)CreateResFromNode(FindResource(name, wxT("wxMenu")), NULL, NULL);
|
|
}
|
|
|
|
|
|
|
|
wxMenuBar *wxXmlResource::LoadMenuBar(wxWindow *parent, const wxString& name)
|
|
{
|
|
return (wxMenuBar*)CreateResFromNode(FindResource(name, wxT("wxMenuBar")), parent, NULL);
|
|
}
|
|
|
|
|
|
|
|
#if wxUSE_TOOLBAR
|
|
wxToolBar *wxXmlResource::LoadToolBar(wxWindow *parent, const wxString& name)
|
|
{
|
|
return (wxToolBar*)CreateResFromNode(FindResource(name, wxT("wxToolBar")), parent, NULL);
|
|
}
|
|
#endif
|
|
|
|
|
|
wxDialog *wxXmlResource::LoadDialog(wxWindow *parent, const wxString& name)
|
|
{
|
|
return (wxDialog*)CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, NULL);
|
|
}
|
|
|
|
bool wxXmlResource::LoadDialog(wxDialog *dlg, wxWindow *parent, const wxString& name)
|
|
{
|
|
return CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, dlg) != NULL;
|
|
}
|
|
|
|
|
|
|
|
wxPanel *wxXmlResource::LoadPanel(wxWindow *parent, const wxString& name)
|
|
{
|
|
return (wxPanel*)CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, NULL);
|
|
}
|
|
|
|
bool wxXmlResource::LoadPanel(wxPanel *panel, wxWindow *parent, const wxString& name)
|
|
{
|
|
return CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, panel) != NULL;
|
|
}
|
|
|
|
wxFrame *wxXmlResource::LoadFrame(wxWindow* parent, const wxString& name)
|
|
{
|
|
return (wxFrame*)CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, NULL);
|
|
}
|
|
|
|
bool wxXmlResource::LoadFrame(wxFrame* frame, wxWindow *parent, const wxString& name)
|
|
{
|
|
return CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, frame) != NULL;
|
|
}
|
|
|
|
wxBitmap wxXmlResource::LoadBitmap(const wxString& name)
|
|
{
|
|
wxBitmap *bmp = (wxBitmap*)CreateResFromNode(
|
|
FindResource(name, wxT("wxBitmap")), NULL, NULL);
|
|
wxBitmap rt;
|
|
|
|
if (bmp) { rt = *bmp; delete bmp; }
|
|
return rt;
|
|
}
|
|
|
|
wxIcon wxXmlResource::LoadIcon(const wxString& name)
|
|
{
|
|
wxIcon *icon = (wxIcon*)CreateResFromNode(
|
|
FindResource(name, wxT("wxIcon")), NULL, NULL);
|
|
wxIcon rt;
|
|
|
|
if (icon) { rt = *icon; delete icon; }
|
|
return rt;
|
|
}
|
|
|
|
|
|
wxObject *wxXmlResource::LoadObject(wxWindow *parent, const wxString& name, const wxString& classname)
|
|
{
|
|
return CreateResFromNode(FindResource(name, classname), parent, NULL);
|
|
}
|
|
|
|
bool wxXmlResource::LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, const wxString& classname)
|
|
{
|
|
return CreateResFromNode(FindResource(name, classname), parent, instance) != NULL;
|
|
}
|
|
|
|
|
|
bool wxXmlResource::AttachUnknownControl(const wxString& name,
|
|
wxWindow *control, wxWindow *parent)
|
|
{
|
|
if (parent == NULL)
|
|
parent = control->GetParent();
|
|
wxWindow *container = parent->FindWindow(name + wxT("_container"));
|
|
if (!container)
|
|
{
|
|
wxLogError(_("Cannot find container for unknown control '%s'."), name.c_str());
|
|
return false;
|
|
}
|
|
return control->Reparent(container);
|
|
}
|
|
|
|
|
|
static void ProcessPlatformProperty(wxXmlNode *node)
|
|
{
|
|
wxString s;
|
|
bool isok;
|
|
|
|
wxXmlNode *c = node->GetChildren();
|
|
while (c)
|
|
{
|
|
isok = false;
|
|
if (!c->GetAttribute(wxT("platform"), &s))
|
|
isok = true;
|
|
else
|
|
{
|
|
wxStringTokenizer tkn(s, wxT(" |"));
|
|
|
|
while (tkn.HasMoreTokens())
|
|
{
|
|
s = tkn.GetNextToken();
|
|
#ifdef __WINDOWS__
|
|
if (s == wxT("win")) isok = true;
|
|
#endif
|
|
#if defined(__MAC__) || defined(__APPLE__)
|
|
if (s == wxT("mac")) isok = true;
|
|
#elif defined(__UNIX__)
|
|
if (s == wxT("unix")) isok = true;
|
|
#endif
|
|
#ifdef __OS2__
|
|
if (s == wxT("os2")) isok = true;
|
|
#endif
|
|
|
|
if (isok)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (isok)
|
|
{
|
|
ProcessPlatformProperty(c);
|
|
c = c->GetNext();
|
|
}
|
|
else
|
|
{
|
|
wxXmlNode *c2 = c->GetNext();
|
|
node->RemoveChild(c);
|
|
delete c;
|
|
c = c2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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 )
|
|
{
|
|
modif = (i->Doc == NULL);
|
|
|
|
if (!modif && !(m_flags & wxXRC_NO_RELOADING))
|
|
{
|
|
# if wxUSE_FILESYSTEM
|
|
file = fsys.OpenFile(i->File);
|
|
# if wxUSE_DATETIME
|
|
modif = file && file->GetModificationTime() > i->Time;
|
|
# else // wxUSE_DATETIME
|
|
modif = true;
|
|
# endif // wxUSE_DATETIME
|
|
if (!file)
|
|
{
|
|
wxLogError(_("Cannot open file '%s'."), i->File.c_str());
|
|
rt = false;
|
|
}
|
|
wxDELETE(file);
|
|
wxUnusedVar(file);
|
|
# else // wxUSE_FILESYSTEM
|
|
# if wxUSE_DATETIME
|
|
modif = wxDateTime(wxFileModificationTime(i->File)) > i->Time;
|
|
# else // wxUSE_DATETIME
|
|
modif = true;
|
|
# endif // wxUSE_DATETIME
|
|
# endif // wxUSE_FILESYSTEM
|
|
}
|
|
|
|
if (modif)
|
|
{
|
|
wxLogTrace(_T("xrc"),
|
|
_T("opening file '%s'"), i->File.c_str());
|
|
|
|
wxInputStream *stream = NULL;
|
|
|
|
# if wxUSE_FILESYSTEM
|
|
file = fsys.OpenFile(i->File);
|
|
if (file)
|
|
stream = file->GetStream();
|
|
# else
|
|
stream = new wxFileInputStream(i->File);
|
|
# endif
|
|
|
|
if (stream)
|
|
{
|
|
delete i->Doc;
|
|
i->Doc = new wxXmlDocument;
|
|
}
|
|
if (!stream || !i->Doc->Load(*stream, encoding))
|
|
{
|
|
wxLogError(_("Cannot load resources from file '%s'."),
|
|
i->File.c_str());
|
|
wxDELETE(i->Doc);
|
|
rt = false;
|
|
}
|
|
else if (i->Doc->GetRoot()->GetName() != wxT("resource"))
|
|
{
|
|
wxLogError(_("Invalid XRC resource '%s': doesn't have root node 'resource'."), i->File.c_str());
|
|
wxDELETE(i->Doc);
|
|
rt = false;
|
|
}
|
|
else
|
|
{
|
|
long version;
|
|
int v1, v2, v3, v4;
|
|
wxString verstr = i->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;
|
|
}
|
|
|
|
ProcessPlatformProperty(i->Doc->GetRoot());
|
|
#if wxUSE_DATETIME
|
|
#if wxUSE_FILESYSTEM
|
|
i->Time = file->GetModificationTime();
|
|
#else // wxUSE_FILESYSTEM
|
|
i->Time = wxDateTime(wxFileModificationTime(i->File));
|
|
#endif // wxUSE_FILESYSTEM
|
|
#endif // wxUSE_DATETIME
|
|
}
|
|
|
|
# if wxUSE_FILESYSTEM
|
|
wxDELETE(file);
|
|
wxUnusedVar(file);
|
|
# else
|
|
wxDELETE(stream);
|
|
# endif
|
|
}
|
|
}
|
|
|
|
return rt;
|
|
}
|
|
|
|
|
|
wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,
|
|
const wxString& name,
|
|
const wxString& classname,
|
|
bool recursive)
|
|
{
|
|
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 )
|
|
{
|
|
wxString cls(node->GetAttribute(wxT("class"), wxEmptyString));
|
|
if (!classname || cls == classname)
|
|
return node;
|
|
// object_ref may not have 'class' attribute:
|
|
if (cls.empty() && node->GetName() == wxT("object_ref"))
|
|
{
|
|
wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString);
|
|
if (refName.empty())
|
|
continue;
|
|
wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
|
|
if (refNode &&
|
|
refNode->GetAttribute(wxT("class"), wxEmptyString) == classname)
|
|
{
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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")) )
|
|
{
|
|
wxXmlNode* found = DoFindResource(node, name, classname, true);
|
|
if ( found )
|
|
return found;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
wxXmlNode *wxXmlResource::FindResource(const wxString& name,
|
|
const wxString& classname,
|
|
bool recursive)
|
|
{
|
|
UpdateResources(); //ensure everything is up-to-date
|
|
|
|
wxString dummy;
|
|
for ( wxXmlResourceDataRecords::const_iterator f = Data().begin();
|
|
f != Data().end(); ++f )
|
|
{
|
|
if ( f->Doc == NULL || f->Doc->GetRoot() == NULL )
|
|
continue;
|
|
|
|
wxXmlNode* found = DoFindResource(f->Doc->GetRoot(),
|
|
name, classname, recursive);
|
|
if ( found )
|
|
{
|
|
#if wxUSE_FILESYSTEM
|
|
m_curFileSystem.ChangePathTo(f->File);
|
|
#endif
|
|
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)
|
|
{
|
|
// Merge attributes:
|
|
for ( wxXmlAttribute *attr = with.GetAttributes();
|
|
attr; attr = attr->GetNext() )
|
|
{
|
|
wxXmlAttribute *dattr;
|
|
for (dattr = dest.GetAttributes(); dattr; dattr = dattr->GetNext())
|
|
{
|
|
|
|
if ( dattr->GetName() == attr->GetName() )
|
|
{
|
|
dattr->SetValue(attr->GetValue());
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !dattr )
|
|
dest.AddAttribute(attr->GetName(), attr->GetValue());
|
|
}
|
|
|
|
// Merge child nodes:
|
|
for (wxXmlNode* node = with.GetChildren(); node; node = node->GetNext())
|
|
{
|
|
wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
|
|
wxXmlNode *dnode;
|
|
|
|
for (dnode = dest.GetChildren(); dnode; dnode = dnode->GetNext() )
|
|
{
|
|
if ( dnode->GetName() == node->GetName() &&
|
|
dnode->GetAttribute(wxT("name"), wxEmptyString) == name &&
|
|
dnode->GetType() == node->GetType() )
|
|
{
|
|
MergeNodes(*dnode, *node);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !dnode )
|
|
{
|
|
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));
|
|
}
|
|
else if ( insert_pos == wxT("begin") )
|
|
{
|
|
dest.InsertChild(new wxXmlNode(*node), dest.GetChildren());
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( dest.GetType() == wxXML_TEXT_NODE && with.GetContent().length() )
|
|
dest.SetContent(with.GetContent());
|
|
}
|
|
|
|
wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
|
|
wxObject *instance,
|
|
wxXmlResourceHandler *handlerToUse)
|
|
{
|
|
if (node == NULL) return NULL;
|
|
|
|
// handling of referenced resource
|
|
if ( node->GetName() == wxT("object_ref") )
|
|
{
|
|
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());
|
|
return NULL;
|
|
}
|
|
|
|
wxXmlNode copy(*refNode);
|
|
MergeNodes(copy, *node);
|
|
|
|
return CreateResFromNode(©, parent, instance);
|
|
}
|
|
|
|
if (handlerToUse)
|
|
{
|
|
if (handlerToUse->CanHandle(node))
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
wxLogError(_("No handler found for XML node '%s', class '%s'!"),
|
|
node->GetName().c_str(),
|
|
node->GetAttribute(wxT("class"), wxEmptyString).c_str());
|
|
return NULL;
|
|
}
|
|
|
|
|
|
class wxXmlSubclassFactories : public wxVector<wxXmlSubclassFactory*>
|
|
{
|
|
// this is a class so that it can be forward-declared
|
|
};
|
|
|
|
wxXmlSubclassFactories *wxXmlResource::ms_subclassFactories = NULL;
|
|
|
|
/*static*/ void wxXmlResource::AddSubclassFactory(wxXmlSubclassFactory *factory)
|
|
{
|
|
if (!ms_subclassFactories)
|
|
{
|
|
ms_subclassFactories = new wxXmlSubclassFactories;
|
|
}
|
|
ms_subclassFactories->push_back(factory);
|
|
}
|
|
|
|
class wxXmlSubclassFactoryCXX : public wxXmlSubclassFactory
|
|
{
|
|
public:
|
|
~wxXmlSubclassFactoryCXX() {}
|
|
|
|
wxObject *Create(const wxString& className)
|
|
{
|
|
wxClassInfo* classInfo = wxClassInfo::FindClass(className);
|
|
|
|
if (classInfo)
|
|
return classInfo->CreateObject();
|
|
else
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
wxXmlResourceHandler::wxXmlResourceHandler()
|
|
: m_node(NULL), m_parent(NULL), m_instance(NULL),
|
|
m_parentAsWindow(NULL)
|
|
{}
|
|
|
|
|
|
|
|
wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance)
|
|
{
|
|
wxXmlNode *myNode = m_node;
|
|
wxString myClass = m_class;
|
|
wxObject *myParent = m_parent, *myInstance = m_instance;
|
|
wxWindow *myParentAW = m_parentAsWindow;
|
|
|
|
m_instance = instance;
|
|
if (!m_instance && node->HasAttribute(wxT("subclass")) &&
|
|
!(m_resource->GetFlags() & wxXRC_NO_SUBCLASSING))
|
|
{
|
|
wxString subclass = node->GetAttribute(wxT("subclass"), wxEmptyString);
|
|
if (!subclass.empty())
|
|
{
|
|
for (wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
|
|
i != wxXmlResource::ms_subclassFactories->end(); ++i)
|
|
{
|
|
m_instance = (*i)->Create(subclass);
|
|
if (m_instance)
|
|
break;
|
|
}
|
|
|
|
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());
|
|
}
|
|
}
|
|
}
|
|
|
|
m_node = node;
|
|
m_class = node->GetAttribute(wxT("class"), wxEmptyString);
|
|
m_parent = parent;
|
|
m_parentAsWindow = wxDynamicCast(m_parent, wxWindow);
|
|
|
|
wxObject *returned = DoCreateResource();
|
|
|
|
m_node = myNode;
|
|
m_class = myClass;
|
|
m_parent = myParent; m_parentAsWindow = myParentAW;
|
|
m_instance = myInstance;
|
|
|
|
return returned;
|
|
}
|
|
|
|
|
|
void wxXmlResourceHandler::AddStyle(const wxString& name, int value)
|
|
{
|
|
m_styleNames.Add(name);
|
|
m_styleValues.Add(value);
|
|
}
|
|
|
|
|
|
|
|
void wxXmlResourceHandler::AddWindowStyles()
|
|
{
|
|
XRC_ADD_STYLE(wxCLIP_CHILDREN);
|
|
|
|
// the border styles all have the old and new names, recognize both for now
|
|
XRC_ADD_STYLE(wxSIMPLE_BORDER); XRC_ADD_STYLE(wxBORDER_SIMPLE);
|
|
XRC_ADD_STYLE(wxSUNKEN_BORDER); XRC_ADD_STYLE(wxBORDER_SUNKEN);
|
|
XRC_ADD_STYLE(wxDOUBLE_BORDER); XRC_ADD_STYLE(wxBORDER_DOUBLE);
|
|
XRC_ADD_STYLE(wxRAISED_BORDER); XRC_ADD_STYLE(wxBORDER_RAISED);
|
|
XRC_ADD_STYLE(wxSTATIC_BORDER); XRC_ADD_STYLE(wxBORDER_STATIC);
|
|
XRC_ADD_STYLE(wxNO_BORDER); XRC_ADD_STYLE(wxBORDER_NONE);
|
|
|
|
XRC_ADD_STYLE(wxTRANSPARENT_WINDOW);
|
|
XRC_ADD_STYLE(wxWANTS_CHARS);
|
|
XRC_ADD_STYLE(wxTAB_TRAVERSAL);
|
|
XRC_ADD_STYLE(wxNO_FULL_REPAINT_ON_RESIZE);
|
|
XRC_ADD_STYLE(wxFULL_REPAINT_ON_RESIZE);
|
|
XRC_ADD_STYLE(wxALWAYS_SHOW_SB);
|
|
XRC_ADD_STYLE(wxWS_EX_BLOCK_EVENTS);
|
|
XRC_ADD_STYLE(wxWS_EX_VALIDATE_RECURSIVELY);
|
|
}
|
|
|
|
|
|
|
|
bool wxXmlResourceHandler::HasParam(const wxString& param)
|
|
{
|
|
return (GetParamNode(param) != NULL);
|
|
}
|
|
|
|
|
|
int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
|
|
{
|
|
wxString s = GetParamValue(param);
|
|
|
|
if (!s) return defaults;
|
|
|
|
wxStringTokenizer tkn(s, wxT("| \t\n"), wxTOKEN_STRTOK);
|
|
int style = 0;
|
|
int index;
|
|
wxString fl;
|
|
while (tkn.HasMoreTokens())
|
|
{
|
|
fl = tkn.GetNextToken();
|
|
index = m_styleNames.Index(fl);
|
|
if (index != wxNOT_FOUND)
|
|
style |= m_styleValues[index];
|
|
else
|
|
wxLogError(_("Unknown style flag ") + fl);
|
|
}
|
|
return style;
|
|
}
|
|
|
|
|
|
|
|
wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate)
|
|
{
|
|
wxXmlNode *parNode = GetParamNode(param);
|
|
wxString str1(GetNodeContent(parNode));
|
|
wxString str2;
|
|
const wxChar *dt;
|
|
wxChar amp_char;
|
|
|
|
// VS: First version of XRC resources used $ instead of & (which is
|
|
// illegal in XML), but later I realized that '_' fits this purpose
|
|
// much better (because &File means "File with F underlined").
|
|
if (m_resource->CompareVersion(2,3,0,1) < 0)
|
|
amp_char = wxT('$');
|
|
else
|
|
amp_char = wxT('_');
|
|
|
|
for (dt = str1.c_str(); *dt; dt++)
|
|
{
|
|
// Remap amp_char to &, map double amp_char to amp_char (for things
|
|
// like "&File..." -- this is illegal in XML, so we use "_File..."):
|
|
if (*dt == amp_char)
|
|
{
|
|
if ( *(++dt) == amp_char )
|
|
str2 << amp_char;
|
|
else
|
|
str2 << wxT('&') << *dt;
|
|
}
|
|
// Remap \n to CR, \r to LF, \t to TAB, \\ to \:
|
|
else if (*dt == wxT('\\'))
|
|
switch (*(++dt))
|
|
{
|
|
case wxT('n'):
|
|
str2 << wxT('\n');
|
|
break;
|
|
|
|
case wxT('t'):
|
|
str2 << wxT('\t');
|
|
break;
|
|
|
|
case wxT('r'):
|
|
str2 << wxT('\r');
|
|
break;
|
|
|
|
case wxT('\\') :
|
|
// "\\" wasn't translated to "\" prior to 2.5.3.0:
|
|
if (m_resource->CompareVersion(2,5,3,0) >= 0)
|
|
{
|
|
str2 << wxT('\\');
|
|
break;
|
|
}
|
|
// else fall-through to default: branch below
|
|
|
|
default:
|
|
str2 << wxT('\\') << *dt;
|
|
break;
|
|
}
|
|
else str2 << *dt;
|
|
}
|
|
|
|
if (m_resource->GetFlags() & wxXRC_USE_LOCALE)
|
|
{
|
|
if (translate && parNode &&
|
|
parNode->GetAttribute(wxT("translate"), wxEmptyString) != wxT("0"))
|
|
{
|
|
return wxGetTranslation(str2, m_resource->GetDomain());
|
|
}
|
|
else
|
|
{
|
|
#if wxUSE_UNICODE
|
|
return str2;
|
|
#else
|
|
// The string is internally stored as UTF-8, we have to convert
|
|
// it into system's default encoding so that it can be displayed:
|
|
return wxString(str2.mb_str(wxConvUTF8), wxConvLocal);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// If wxXRC_USE_LOCALE is not set, then the string is already in
|
|
// system's default encoding in ANSI build, so we don't have to
|
|
// do anything special here.
|
|
return str2;
|
|
}
|
|
|
|
|
|
|
|
long wxXmlResourceHandler::GetLong(const wxString& param, long defaultv)
|
|
{
|
|
long value;
|
|
wxString str1 = GetParamValue(param);
|
|
|
|
if (!str1.ToLong(&value))
|
|
value = defaultv;
|
|
|
|
return value;
|
|
}
|
|
|
|
float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv)
|
|
{
|
|
wxString str = GetParamValue(param);
|
|
|
|
// 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));
|
|
|
|
double value;
|
|
if (!str.ToDouble(&value))
|
|
value = defaultv;
|
|
|
|
return wx_truncate_cast(float, value);
|
|
}
|
|
|
|
|
|
int wxXmlResourceHandler::GetID()
|
|
{
|
|
return wxXmlResource::GetXRCID(GetName());
|
|
}
|
|
|
|
|
|
|
|
wxString wxXmlResourceHandler::GetName()
|
|
{
|
|
return m_node->GetAttribute(wxT("name"), wxT("-1"));
|
|
}
|
|
|
|
|
|
|
|
bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv)
|
|
{
|
|
wxString v = GetParamValue(param);
|
|
v.MakeLower();
|
|
if (!v) return defaultv;
|
|
|
|
return (v == wxT("1"));
|
|
}
|
|
|
|
|
|
static wxColour GetSystemColour(const wxString& name)
|
|
{
|
|
if (!name.empty())
|
|
{
|
|
#define SYSCLR(clr) \
|
|
if (name == _T(#clr)) return wxSystemSettings::GetColour(clr);
|
|
SYSCLR(wxSYS_COLOUR_SCROLLBAR)
|
|
SYSCLR(wxSYS_COLOUR_BACKGROUND)
|
|
SYSCLR(wxSYS_COLOUR_DESKTOP)
|
|
SYSCLR(wxSYS_COLOUR_ACTIVECAPTION)
|
|
SYSCLR(wxSYS_COLOUR_INACTIVECAPTION)
|
|
SYSCLR(wxSYS_COLOUR_MENU)
|
|
SYSCLR(wxSYS_COLOUR_WINDOW)
|
|
SYSCLR(wxSYS_COLOUR_WINDOWFRAME)
|
|
SYSCLR(wxSYS_COLOUR_MENUTEXT)
|
|
SYSCLR(wxSYS_COLOUR_WINDOWTEXT)
|
|
SYSCLR(wxSYS_COLOUR_CAPTIONTEXT)
|
|
SYSCLR(wxSYS_COLOUR_ACTIVEBORDER)
|
|
SYSCLR(wxSYS_COLOUR_INACTIVEBORDER)
|
|
SYSCLR(wxSYS_COLOUR_APPWORKSPACE)
|
|
SYSCLR(wxSYS_COLOUR_HIGHLIGHT)
|
|
SYSCLR(wxSYS_COLOUR_HIGHLIGHTTEXT)
|
|
SYSCLR(wxSYS_COLOUR_BTNFACE)
|
|
SYSCLR(wxSYS_COLOUR_3DFACE)
|
|
SYSCLR(wxSYS_COLOUR_BTNSHADOW)
|
|
SYSCLR(wxSYS_COLOUR_3DSHADOW)
|
|
SYSCLR(wxSYS_COLOUR_GRAYTEXT)
|
|
SYSCLR(wxSYS_COLOUR_BTNTEXT)
|
|
SYSCLR(wxSYS_COLOUR_INACTIVECAPTIONTEXT)
|
|
SYSCLR(wxSYS_COLOUR_BTNHIGHLIGHT)
|
|
SYSCLR(wxSYS_COLOUR_BTNHILIGHT)
|
|
SYSCLR(wxSYS_COLOUR_3DHIGHLIGHT)
|
|
SYSCLR(wxSYS_COLOUR_3DHILIGHT)
|
|
SYSCLR(wxSYS_COLOUR_3DDKSHADOW)
|
|
SYSCLR(wxSYS_COLOUR_3DLIGHT)
|
|
SYSCLR(wxSYS_COLOUR_INFOTEXT)
|
|
SYSCLR(wxSYS_COLOUR_INFOBK)
|
|
SYSCLR(wxSYS_COLOUR_LISTBOX)
|
|
SYSCLR(wxSYS_COLOUR_HOTLIGHT)
|
|
SYSCLR(wxSYS_COLOUR_GRADIENTACTIVECAPTION)
|
|
SYSCLR(wxSYS_COLOUR_GRADIENTINACTIVECAPTION)
|
|
SYSCLR(wxSYS_COLOUR_MENUHILIGHT)
|
|
SYSCLR(wxSYS_COLOUR_MENUBAR)
|
|
#undef SYSCLR
|
|
}
|
|
|
|
return wxNullColour;
|
|
}
|
|
|
|
wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& defaultv)
|
|
{
|
|
wxString v = GetParamValue(param);
|
|
|
|
if ( v.empty() )
|
|
return defaultv;
|
|
|
|
wxColour clr;
|
|
|
|
// wxString -> wxColour conversion
|
|
if (!clr.Set(v))
|
|
{
|
|
// the colour doesn't use #RRGGBB format, check if it is symbolic
|
|
// colour name:
|
|
clr = GetSystemColour(v);
|
|
if (clr.Ok())
|
|
return clr;
|
|
|
|
wxLogError(_("XRC resource: Incorrect colour specification '%s' for attribute '%s'."),
|
|
v.c_str(), param.c_str());
|
|
return wxNullColour;
|
|
}
|
|
|
|
return clr;
|
|
}
|
|
|
|
|
|
|
|
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 )
|
|
{
|
|
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);
|
|
|
|
wxBitmap stockArt =
|
|
wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(sid),
|
|
scl, size);
|
|
if ( stockArt.Ok() )
|
|
return stockArt;
|
|
}
|
|
}
|
|
|
|
/* ...or load the bitmap from file: */
|
|
wxString name = GetParamValue(param);
|
|
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());
|
|
return wxNullBitmap;
|
|
}
|
|
wxImage img(*(fsfile->GetStream()));
|
|
delete fsfile;
|
|
#else
|
|
wxImage img(name);
|
|
#endif
|
|
|
|
if (!img.Ok())
|
|
{
|
|
wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
|
|
name.c_str());
|
|
return wxNullBitmap;
|
|
}
|
|
if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
|
|
return wxBitmap(img);
|
|
}
|
|
|
|
#if wxUSE_ANIMATIONCTRL
|
|
wxAnimation wxXmlResourceHandler::GetAnimation(const wxString& param)
|
|
{
|
|
wxAnimation ani;
|
|
|
|
/* load the animation from file: */
|
|
wxString name = GetParamValue(param);
|
|
if (name.empty()) return wxNullAnimation;
|
|
#if wxUSE_FILESYSTEM
|
|
wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
|
|
if (fsfile == NULL)
|
|
{
|
|
wxLogError(_("XRC resource: Cannot create animation from '%s'."),
|
|
name.c_str());
|
|
return wxNullAnimation;
|
|
}
|
|
ani.Load(*(fsfile->GetStream()));
|
|
delete fsfile;
|
|
#else
|
|
ani.LoadFile(name);
|
|
#endif
|
|
|
|
if (!ani.IsOk())
|
|
{
|
|
wxLogError(_("XRC resource: Cannot create animation from '%s'."),
|
|
name.c_str());
|
|
return wxNullAnimation;
|
|
}
|
|
|
|
return ani;
|
|
}
|
|
#endif // wxUSE_ANIMATIONCTRL
|
|
|
|
|
|
|
|
wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
|
|
const wxArtClient& defaultArtClient,
|
|
wxSize size)
|
|
{
|
|
wxIcon icon;
|
|
icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size));
|
|
return icon;
|
|
}
|
|
|
|
|
|
|
|
wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
|
|
{
|
|
wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!"));
|
|
|
|
wxXmlNode *n = m_node->GetChildren();
|
|
|
|
while (n)
|
|
{
|
|
if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
|
|
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)
|
|
{
|
|
wxXmlNode *n = node;
|
|
if (n == NULL) return wxEmptyString;
|
|
n = n->GetChildren();
|
|
|
|
while (n)
|
|
{
|
|
if (n->GetType() == wxXML_TEXT_NODE ||
|
|
n->GetType() == wxXML_CDATA_SECTION_NODE)
|
|
return n->GetContent();
|
|
n = n->GetNext();
|
|
}
|
|
return wxEmptyString;
|
|
}
|
|
|
|
|
|
|
|
wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
|
|
{
|
|
if (param.empty())
|
|
return GetNodeContent(m_node);
|
|
else
|
|
return GetNodeContent(GetParamNode(param));
|
|
}
|
|
|
|
|
|
|
|
wxSize wxXmlResourceHandler::GetSize(const wxString& param,
|
|
wxWindow *windowToUse)
|
|
{
|
|
wxString s = GetParamValue(param);
|
|
if (s.empty()) s = wxT("-1,-1");
|
|
bool is_dlg;
|
|
long sx, sy = 0;
|
|
|
|
is_dlg = s[s.length()-1] == wxT('d');
|
|
if (is_dlg) s.RemoveLast();
|
|
|
|
if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
|
|
!s.AfterLast(wxT(',')).ToLong(&sy))
|
|
{
|
|
wxLogError(_("Cannot parse coordinates from '%s'."), s.c_str());
|
|
return wxDefaultSize;
|
|
}
|
|
|
|
if (is_dlg)
|
|
{
|
|
if (windowToUse)
|
|
{
|
|
return wxDLG_UNIT(windowToUse, wxSize(sx, sy));
|
|
}
|
|
else if (m_parentAsWindow)
|
|
{
|
|
return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, sy));
|
|
}
|
|
else
|
|
{
|
|
wxLogError(_("Cannot convert dialog units: dialog unknown."));
|
|
return wxDefaultSize;
|
|
}
|
|
}
|
|
|
|
return wxSize(sx, sy);
|
|
}
|
|
|
|
|
|
|
|
wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
|
|
{
|
|
wxSize sz = GetSize(param);
|
|
return wxPoint(sz.x, sz.y);
|
|
}
|
|
|
|
|
|
|
|
wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
|
|
wxCoord defaultv,
|
|
wxWindow *windowToUse)
|
|
{
|
|
wxString s = GetParamValue(param);
|
|
if (s.empty()) return defaultv;
|
|
bool is_dlg;
|
|
long sx;
|
|
|
|
is_dlg = s[s.length()-1] == wxT('d');
|
|
if (is_dlg) s.RemoveLast();
|
|
|
|
if (!s.ToLong(&sx))
|
|
{
|
|
wxLogError(_("Cannot parse dimension from '%s'."), s.c_str());
|
|
return defaultv;
|
|
}
|
|
|
|
if (is_dlg)
|
|
{
|
|
if (windowToUse)
|
|
{
|
|
return wxDLG_UNIT(windowToUse, wxSize(sx, 0)).x;
|
|
}
|
|
else if (m_parentAsWindow)
|
|
{
|
|
return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, 0)).x;
|
|
}
|
|
else
|
|
{
|
|
wxLogError(_("Cannot convert dialog units: dialog unknown."));
|
|
return defaultv;
|
|
}
|
|
}
|
|
|
|
return sx;
|
|
}
|
|
|
|
|
|
// 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);
|
|
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
|
|
}
|
|
|
|
return wxNullFont;
|
|
}
|
|
|
|
wxFont wxXmlResourceHandler::GetFont(const wxString& param)
|
|
{
|
|
wxXmlNode *font_node = GetParamNode(param);
|
|
if (font_node == NULL)
|
|
{
|
|
wxLogError(_("Cannot find font node '%s'."), param.c_str());
|
|
return wxNullFont;
|
|
}
|
|
|
|
wxXmlNode *oldnode = m_node;
|
|
m_node = font_node;
|
|
|
|
// font attributes:
|
|
|
|
// size
|
|
int isize = -1;
|
|
bool hasSize = HasParam(wxT("size"));
|
|
if (hasSize)
|
|
isize = GetLong(wxT("size"), -1);
|
|
|
|
// style
|
|
int istyle = wxNORMAL;
|
|
bool hasStyle = HasParam(wxT("style"));
|
|
if (hasStyle)
|
|
{
|
|
wxString style = GetParamValue(wxT("style"));
|
|
if (style == wxT("italic"))
|
|
istyle = wxITALIC;
|
|
else if (style == wxT("slant"))
|
|
istyle = wxSLANT;
|
|
}
|
|
|
|
// weight
|
|
int iweight = wxNORMAL;
|
|
bool hasWeight = HasParam(wxT("weight"));
|
|
if (hasWeight)
|
|
{
|
|
wxString weight = GetParamValue(wxT("weight"));
|
|
if (weight == wxT("bold"))
|
|
iweight = wxBOLD;
|
|
else if (weight == wxT("light"))
|
|
iweight = wxLIGHT;
|
|
}
|
|
|
|
// underline
|
|
bool hasUnderlined = HasParam(wxT("underlined"));
|
|
bool underlined = hasUnderlined ? GetBool(wxT("underlined"), false) : false;
|
|
|
|
// family and facename
|
|
int ifamily = wxDEFAULT;
|
|
bool hasFamily = HasParam(wxT("family"));
|
|
if (hasFamily)
|
|
{
|
|
wxString family = GetParamValue(wxT("family"));
|
|
if (family == wxT("decorative")) ifamily = wxDECORATIVE;
|
|
else if (family == wxT("roman")) ifamily = wxROMAN;
|
|
else if (family == wxT("script")) ifamily = wxSCRIPT;
|
|
else if (family == wxT("swiss")) ifamily = wxSWISS;
|
|
else if (family == wxT("modern")) ifamily = wxMODERN;
|
|
else if (family == wxT("teletype")) ifamily = wxTELETYPE;
|
|
}
|
|
|
|
|
|
wxString facename;
|
|
bool hasFacename = HasParam(wxT("face"));
|
|
if (hasFacename)
|
|
{
|
|
wxString faces = GetParamValue(wxT("face"));
|
|
wxArrayString facenames(wxFontEnumerator::GetFacenames());
|
|
wxStringTokenizer tk(faces, wxT(","));
|
|
while (tk.HasMoreTokens())
|
|
{
|
|
int index = facenames.Index(tk.GetNextToken(), false);
|
|
if (index != wxNOT_FOUND)
|
|
{
|
|
facename = facenames[index];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// encoding
|
|
wxFontEncoding enc = wxFONTENCODING_DEFAULT;
|
|
bool hasEncoding = HasParam(wxT("encoding"));
|
|
if (hasEncoding)
|
|
{
|
|
wxString encoding = GetParamValue(wxT("encoding"));
|
|
wxFontMapper mapper;
|
|
if (!encoding.empty())
|
|
enc = mapper.CharsetToEncoding(encoding);
|
|
if (enc == wxFONTENCODING_SYSTEM)
|
|
enc = wxFONTENCODING_DEFAULT;
|
|
}
|
|
|
|
// is this font based on a system font?
|
|
wxFont font = GetSystemFont(GetParamValue(wxT("sysfont")));
|
|
|
|
if (font.Ok())
|
|
{
|
|
if (hasSize && isize != -1)
|
|
font.SetPointSize(isize);
|
|
else if (HasParam(wxT("relativesize")))
|
|
font.SetPointSize(int(font.GetPointSize() *
|
|
GetFloat(wxT("relativesize"))));
|
|
|
|
if (hasStyle)
|
|
font.SetStyle(istyle);
|
|
if (hasWeight)
|
|
font.SetWeight(iweight);
|
|
if (hasUnderlined)
|
|
font.SetUnderlined(underlined);
|
|
if (hasFamily)
|
|
font.SetFamily(ifamily);
|
|
if (hasFacename)
|
|
font.SetFaceName(facename);
|
|
if (hasEncoding)
|
|
font.SetDefaultEncoding(enc);
|
|
}
|
|
else // not based on system font
|
|
{
|
|
font = wxFont(isize == -1 ? wxNORMAL_FONT->GetPointSize() : isize,
|
|
ifamily, istyle, iweight,
|
|
underlined, facename, enc);
|
|
}
|
|
|
|
m_node = oldnode;
|
|
return font;
|
|
}
|
|
|
|
|
|
void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
|
|
{
|
|
//FIXME : add cursor
|
|
|
|
if (HasParam(wxT("exstyle")))
|
|
// Have to OR it with existing style, since
|
|
// some implementations (e.g. wxGTK) use the extra style
|
|
// during creation
|
|
wnd->SetExtraStyle(wnd->GetExtraStyle() | GetStyle(wxT("exstyle")));
|
|
if (HasParam(wxT("bg")))
|
|
wnd->SetBackgroundColour(GetColour(wxT("bg")));
|
|
if (HasParam(wxT("fg")))
|
|
wnd->SetForegroundColour(GetColour(wxT("fg")));
|
|
if (GetBool(wxT("enabled"), 1) == 0)
|
|
wnd->Enable(false);
|
|
if (GetBool(wxT("focused"), 0) == 1)
|
|
wnd->SetFocus();
|
|
if (GetBool(wxT("hidden"), 0) == 1)
|
|
wnd->Show(false);
|
|
#if wxUSE_TOOLTIPS
|
|
if (HasParam(wxT("tooltip")))
|
|
wnd->SetToolTip(GetText(wxT("tooltip")));
|
|
#endif
|
|
if (HasParam(wxT("font")))
|
|
wnd->SetFont(GetFont());
|
|
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)
|
|
{
|
|
if (n->GetType() == wxXML_ELEMENT_NODE &&
|
|
(n->GetName() == wxT("object") || n->GetName() == wxT("object_ref")))
|
|
{
|
|
m_resource->CreateResFromNode(n, parent, NULL,
|
|
this_hnd_only ? this : NULL);
|
|
}
|
|
n = n->GetNext();
|
|
}
|
|
}
|
|
|
|
|
|
void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode)
|
|
{
|
|
wxXmlNode *root;
|
|
if (rootnode == NULL) root = m_node; else root = rootnode;
|
|
wxXmlNode *n = root->GetChildren();
|
|
|
|
while (n)
|
|
{
|
|
if (n->GetType() == wxXML_ELEMENT_NODE && CanHandle(n))
|
|
{
|
|
CreateResource(n, parent, NULL);
|
|
}
|
|
n = n->GetNext();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --------------- XRCID implementation -----------------------------
|
|
|
|
#define XRCID_TABLE_SIZE 1024
|
|
|
|
|
|
struct XRCID_record
|
|
{
|
|
int id;
|
|
char *key;
|
|
XRCID_record *next;
|
|
};
|
|
|
|
static XRCID_record *XRCID_Records[XRCID_TABLE_SIZE] = {NULL};
|
|
|
|
static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE)
|
|
{
|
|
int index = 0;
|
|
|
|
for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
|
|
index %= XRCID_TABLE_SIZE;
|
|
|
|
XRCID_record *oldrec = NULL;
|
|
for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
|
|
{
|
|
if (wxStrcmp(rec->key, str_id) == 0)
|
|
{
|
|
return rec->id;
|
|
}
|
|
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)->next = NULL;
|
|
|
|
char *end;
|
|
if (value_if_not_found != wxID_NONE)
|
|
(*rec_var)->id = value_if_not_found;
|
|
else
|
|
{
|
|
int asint = wxStrtol(str_id, &end, 10);
|
|
if (*str_id && *end == 0)
|
|
{
|
|
// if str_id was integer, keep it verbosely:
|
|
(*rec_var)->id = asint;
|
|
}
|
|
else
|
|
{
|
|
(*rec_var)->id = wxNewId();
|
|
}
|
|
}
|
|
|
|
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 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()
|
|
{
|
|
#define stdID(id) XRCID_Lookup(#id, id)
|
|
stdID(-1);
|
|
|
|
stdID(wxID_ANY);
|
|
stdID(wxID_SEPARATOR);
|
|
|
|
stdID(wxID_OPEN);
|
|
stdID(wxID_CLOSE);
|
|
stdID(wxID_NEW);
|
|
stdID(wxID_SAVE);
|
|
stdID(wxID_SAVEAS);
|
|
stdID(wxID_REVERT);
|
|
stdID(wxID_EXIT);
|
|
stdID(wxID_UNDO);
|
|
stdID(wxID_REDO);
|
|
stdID(wxID_HELP);
|
|
stdID(wxID_PRINT);
|
|
stdID(wxID_PRINT_SETUP);
|
|
stdID(wxID_PAGE_SETUP);
|
|
stdID(wxID_PREVIEW);
|
|
stdID(wxID_ABOUT);
|
|
stdID(wxID_HELP_CONTENTS);
|
|
stdID(wxID_HELP_COMMANDS);
|
|
stdID(wxID_HELP_PROCEDURES);
|
|
stdID(wxID_HELP_CONTEXT);
|
|
stdID(wxID_CLOSE_ALL);
|
|
stdID(wxID_PREFERENCES);
|
|
stdID(wxID_CUT);
|
|
stdID(wxID_COPY);
|
|
stdID(wxID_PASTE);
|
|
stdID(wxID_CLEAR);
|
|
stdID(wxID_FIND);
|
|
stdID(wxID_DUPLICATE);
|
|
stdID(wxID_SELECTALL);
|
|
stdID(wxID_DELETE);
|
|
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_LIST);
|
|
stdID(wxID_VIEW_SORTDATE);
|
|
stdID(wxID_VIEW_SORTNAME);
|
|
stdID(wxID_VIEW_SORTSIZE);
|
|
stdID(wxID_VIEW_SORTTYPE);
|
|
stdID(wxID_FILE1);
|
|
stdID(wxID_FILE2);
|
|
stdID(wxID_FILE3);
|
|
stdID(wxID_FILE4);
|
|
stdID(wxID_FILE5);
|
|
stdID(wxID_FILE6);
|
|
stdID(wxID_FILE7);
|
|
stdID(wxID_FILE8);
|
|
stdID(wxID_FILE9);
|
|
stdID(wxID_OK);
|
|
stdID(wxID_CANCEL);
|
|
stdID(wxID_APPLY);
|
|
stdID(wxID_YES);
|
|
stdID(wxID_NO);
|
|
stdID(wxID_STATIC);
|
|
stdID(wxID_FORWARD);
|
|
stdID(wxID_BACKWARD);
|
|
stdID(wxID_DEFAULT);
|
|
stdID(wxID_MORE);
|
|
stdID(wxID_SETUP);
|
|
stdID(wxID_RESET);
|
|
stdID(wxID_CONTEXT_HELP);
|
|
stdID(wxID_YESTOALL);
|
|
stdID(wxID_NOTOALL);
|
|
stdID(wxID_ABORT);
|
|
stdID(wxID_RETRY);
|
|
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_JUSTIFY_FILL);
|
|
stdID(wxID_JUSTIFY_RIGHT);
|
|
stdID(wxID_JUSTIFY_LEFT);
|
|
stdID(wxID_UNDERLINE);
|
|
stdID(wxID_INDENT);
|
|
stdID(wxID_UNINDENT);
|
|
stdID(wxID_ZOOM_100);
|
|
stdID(wxID_ZOOM_FIT);
|
|
stdID(wxID_ZOOM_IN);
|
|
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);
|
|
|
|
#undef stdID
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --------------- module and globals -----------------------------
|
|
|
|
class wxXmlResourceModule: public wxModule
|
|
{
|
|
DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
|
|
public:
|
|
wxXmlResourceModule() {}
|
|
bool OnInit()
|
|
{
|
|
wxXmlResource::AddSubclassFactory(new wxXmlSubclassFactoryCXX);
|
|
return true;
|
|
}
|
|
void OnExit()
|
|
{
|
|
delete wxXmlResource::Set(NULL);
|
|
if(wxXmlResource::ms_subclassFactories)
|
|
{
|
|
for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
|
|
i != wxXmlResource::ms_subclassFactories->end(); ++i )
|
|
{
|
|
delete *i;
|
|
}
|
|
wxDELETE(wxXmlResource::ms_subclassFactories);
|
|
}
|
|
CleanXRCID_Records();
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)
|
|
|
|
|
|
// When wxXml is loaded dynamically after the application is already running
|
|
// then the built-in module system won't pick this one up. Add it manually.
|
|
void wxXmlInitResourceModule()
|
|
{
|
|
wxModule* module = new wxXmlResourceModule;
|
|
module->Init();
|
|
wxModule::RegisterModule(module);
|
|
}
|
|
|
|
#endif // wxUSE_XRC
|