1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/xrc/xmlres.cpp
3// Purpose:     XRC resources
4// Author:      Vaclav Slavik
5// Created:     2000/03/05
6// RCS-ID:      $Id: xmlres.cpp 63465 2010-02-11 12:36:43Z VS $
7// Copyright:   (c) 2000 Vaclav Slavik
8// Licence:     wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// For compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15    #pragma hdrstop
16#endif
17
18#if wxUSE_XRC
19
20#include "wx/xrc/xmlres.h"
21
22#ifndef WX_PRECOMP
23    #include "wx/intl.h"
24    #include "wx/log.h"
25    #include "wx/panel.h"
26    #include "wx/frame.h"
27    #include "wx/dialog.h"
28    #include "wx/settings.h"
29    #include "wx/bitmap.h"
30    #include "wx/image.h"
31    #include "wx/module.h"
32#endif
33
34#ifndef __WXWINCE__
35    #include <locale.h>
36#endif
37
38#include "wx/wfstream.h"
39#include "wx/filesys.h"
40#include "wx/filename.h"
41#include "wx/tokenzr.h"
42#include "wx/fontenum.h"
43#include "wx/fontmap.h"
44#include "wx/artprov.h"
45
46#include "wx/xml/xml.h"
47
48#include "wx/arrimpl.cpp"
49WX_DEFINE_OBJARRAY(wxXmlResourceDataRecords)
50
51
52wxXmlResource *wxXmlResource::ms_instance = NULL;
53
54/*static*/ wxXmlResource *wxXmlResource::Get()
55{
56    if ( !ms_instance )
57        ms_instance = new wxXmlResource;
58    return ms_instance;
59}
60
61/*static*/ wxXmlResource *wxXmlResource::Set(wxXmlResource *res)
62{
63    wxXmlResource *old = ms_instance;
64    ms_instance = res;
65    return old;
66}
67
68wxXmlResource::wxXmlResource(int flags, const wxString& domain)
69{
70    m_flags = flags;
71    m_version = -1;
72    m_domain = NULL;
73    if (! domain.empty() )
74        SetDomain(domain);
75}
76
77wxXmlResource::wxXmlResource(const wxString& filemask, int flags, const wxString& domain)
78{
79    m_flags = flags;
80    m_version = -1;
81    m_domain = NULL;
82    if (! domain.empty() )
83        SetDomain(domain);
84    Load(filemask);
85}
86
87wxXmlResource::~wxXmlResource()
88{
89    if (m_domain)
90        free(m_domain);
91    ClearHandlers();
92}
93
94void wxXmlResource::SetDomain(const wxChar* domain)
95{
96    if (m_domain)
97        free(m_domain);
98    m_domain = NULL;
99    if (domain && wxStrlen(domain))
100        m_domain = wxStrdup(domain);
101}
102
103
104/* static */
105wxString wxXmlResource::ConvertFileNameToURL(const wxString& filename)
106{
107    wxString fnd(filename);
108
109    // NB: as Load() and Unload() accept both filenames and URLs (should
110    //     probably be changed to filenames only, but embedded resources
111    //     currently rely on its ability to handle URLs - FIXME) we need to
112    //     determine whether found name is filename and not URL and this is the
113    //     fastest/simplest way to do it
114    if (wxFileName::FileExists(fnd))
115    {
116        // Make the name absolute filename, because the app may
117        // change working directory later:
118        wxFileName fn(fnd);
119        if (fn.IsRelative())
120        {
121            fn.MakeAbsolute();
122            fnd = fn.GetFullPath();
123        }
124#if wxUSE_FILESYSTEM
125        fnd = wxFileSystem::FileNameToURL(fnd);
126#endif
127    }
128
129    return fnd;
130}
131
132#if wxUSE_FILESYSTEM
133
134/* static */
135bool wxXmlResource::IsArchive(const wxString& filename)
136{
137    const wxString fnd = filename.Lower();
138
139    return fnd.Matches(wxT("*.zip")) || fnd.Matches(wxT("*.xrs"));
140}
141
142#endif // wxUSE_FILESYSTEM
143
144bool wxXmlResource::Load(const wxString& filemask)
145{
146    wxString fnd;
147    wxXmlResourceDataRecord *drec;
148    bool iswild = wxIsWild(filemask);
149    bool rt = true;
150
151#if wxUSE_FILESYSTEM
152    wxFileSystem fsys;
153#   define wxXmlFindFirst  fsys.FindFirst(filemask, wxFILE)
154#   define wxXmlFindNext   fsys.FindNext()
155#else
156#   define wxXmlFindFirst  wxFindFirstFile(filemask, wxFILE)
157#   define wxXmlFindNext   wxFindNextFile()
158#endif
159    if (iswild)
160        fnd = wxXmlFindFirst;
161    else
162        fnd = filemask;
163    while (!fnd.empty())
164    {
165        fnd = ConvertFileNameToURL(fnd);
166
167#if wxUSE_FILESYSTEM
168        if ( IsArchive(fnd) )
169        {
170            rt = rt && Load(fnd + wxT("#zip:*.xrc"));
171        }
172        else // a single resource URL
173#endif // wxUSE_FILESYSTEM
174        {
175            drec = new wxXmlResourceDataRecord;
176            drec->File = fnd;
177            m_data.Add(drec);
178        }
179
180        if (iswild)
181            fnd = wxXmlFindNext;
182        else
183            fnd = wxEmptyString;
184    }
185#   undef wxXmlFindFirst
186#   undef wxXmlFindNext
187    return rt && UpdateResources();
188}
189
190bool wxXmlResource::Unload(const wxString& filename)
191{
192    wxASSERT_MSG( !wxIsWild(filename),
193                    _T("wildcards not supported by wxXmlResource::Unload()") );
194
195    wxString fnd = ConvertFileNameToURL(filename);
196#if wxUSE_FILESYSTEM
197    const bool isArchive = IsArchive(fnd);
198    if ( isArchive )
199        fnd += _T("#zip:");
200#endif // wxUSE_FILESYSTEM
201
202    bool unloaded = false;
203    const size_t count = m_data.GetCount();
204    for ( size_t i = 0; i < count; i++ )
205    {
206#if wxUSE_FILESYSTEM
207        if ( isArchive )
208        {
209            if ( m_data[i].File.StartsWith(fnd) )
210                unloaded = true;
211            // don't break from the loop, we can have other matching files
212        }
213        else // a single resource URL
214#endif // wxUSE_FILESYSTEM
215        {
216            if ( m_data[i].File == fnd )
217            {
218                m_data.RemoveAt(i);
219                unloaded = true;
220
221                // no sense in continuing, there is only one file with this URL
222                break;
223            }
224        }
225    }
226
227    return unloaded;
228}
229
230
231IMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject)
232
233void wxXmlResource::AddHandler(wxXmlResourceHandler *handler)
234{
235    m_handlers.Append(handler);
236    handler->SetParentResource(this);
237}
238
239void wxXmlResource::InsertHandler(wxXmlResourceHandler *handler)
240{
241    m_handlers.Insert(handler);
242    handler->SetParentResource(this);
243}
244
245
246
247void wxXmlResource::ClearHandlers()
248{
249    WX_CLEAR_LIST(wxList, m_handlers);
250}
251
252
253wxMenu *wxXmlResource::LoadMenu(const wxString& name)
254{
255    return (wxMenu*)CreateResFromNode(FindResource(name, wxT("wxMenu")), NULL, NULL);
256}
257
258
259
260wxMenuBar *wxXmlResource::LoadMenuBar(wxWindow *parent, const wxString& name)
261{
262    return (wxMenuBar*)CreateResFromNode(FindResource(name, wxT("wxMenuBar")), parent, NULL);
263}
264
265
266
267#if wxUSE_TOOLBAR
268wxToolBar *wxXmlResource::LoadToolBar(wxWindow *parent, const wxString& name)
269{
270    return (wxToolBar*)CreateResFromNode(FindResource(name, wxT("wxToolBar")), parent, NULL);
271}
272#endif
273
274
275wxDialog *wxXmlResource::LoadDialog(wxWindow *parent, const wxString& name)
276{
277    return (wxDialog*)CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, NULL);
278}
279
280bool wxXmlResource::LoadDialog(wxDialog *dlg, wxWindow *parent, const wxString& name)
281{
282    return CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, dlg) != NULL;
283}
284
285
286
287wxPanel *wxXmlResource::LoadPanel(wxWindow *parent, const wxString& name)
288{
289    return (wxPanel*)CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, NULL);
290}
291
292bool wxXmlResource::LoadPanel(wxPanel *panel, wxWindow *parent, const wxString& name)
293{
294    return CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, panel) != NULL;
295}
296
297wxFrame *wxXmlResource::LoadFrame(wxWindow* parent, const wxString& name)
298{
299    return (wxFrame*)CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, NULL);
300}
301
302bool wxXmlResource::LoadFrame(wxFrame* frame, wxWindow *parent, const wxString& name)
303{
304    return CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, frame) != NULL;
305}
306
307wxBitmap wxXmlResource::LoadBitmap(const wxString& name)
308{
309    wxBitmap *bmp = (wxBitmap*)CreateResFromNode(
310                               FindResource(name, wxT("wxBitmap")), NULL, NULL);
311    wxBitmap rt;
312
313    if (bmp) { rt = *bmp; delete bmp; }
314    return rt;
315}
316
317wxIcon wxXmlResource::LoadIcon(const wxString& name)
318{
319    wxIcon *icon = (wxIcon*)CreateResFromNode(
320                            FindResource(name, wxT("wxIcon")), NULL, NULL);
321    wxIcon rt;
322
323    if (icon) { rt = *icon; delete icon; }
324    return rt;
325}
326
327
328wxObject *wxXmlResource::LoadObject(wxWindow *parent, const wxString& name, const wxString& classname)
329{
330    return CreateResFromNode(FindResource(name, classname), parent, NULL);
331}
332
333bool wxXmlResource::LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, const wxString& classname)
334{
335    return CreateResFromNode(FindResource(name, classname), parent, instance) != NULL;
336}
337
338
339bool wxXmlResource::AttachUnknownControl(const wxString& name,
340                                         wxWindow *control, wxWindow *parent)
341{
342    if (parent == NULL)
343        parent = control->GetParent();
344    wxWindow *container = parent->FindWindow(name + wxT("_container"));
345    if (!container)
346    {
347        wxLogError(_("Cannot find container for unknown control '%s'."), name.c_str());
348        return false;
349    }
350    return control->Reparent(container);
351}
352
353
354static void ProcessPlatformProperty(wxXmlNode *node)
355{
356    wxString s;
357    bool isok;
358
359    wxXmlNode *c = node->GetChildren();
360    while (c)
361    {
362        isok = false;
363        if (!c->GetPropVal(wxT("platform"), &s))
364            isok = true;
365        else
366        {
367            wxStringTokenizer tkn(s, wxT(" |"));
368
369            while (tkn.HasMoreTokens())
370            {
371                s = tkn.GetNextToken();
372#ifdef __WINDOWS__
373                if (s == wxT("win")) isok = true;
374#endif
375#if defined(__MAC__) || defined(__APPLE__)
376                if (s == wxT("mac")) isok = true;
377#elif defined(__UNIX__)
378                if (s == wxT("unix")) isok = true;
379#endif
380#ifdef __OS2__
381                if (s == wxT("os2")) isok = true;
382#endif
383
384                if (isok)
385                    break;
386            }
387        }
388
389        if (isok)
390        {
391            ProcessPlatformProperty(c);
392            c = c->GetNext();
393        }
394        else
395        {
396            wxXmlNode *c2 = c->GetNext();
397            node->RemoveChild(c);
398            delete c;
399            c = c2;
400        }
401    }
402}
403
404
405
406bool wxXmlResource::UpdateResources()
407{
408    bool rt = true;
409    bool modif;
410#   if wxUSE_FILESYSTEM
411    wxFSFile *file = NULL;
412    wxUnusedVar(file);
413    wxFileSystem fsys;
414#   endif
415
416    wxString encoding(wxT("UTF-8"));
417#if !wxUSE_UNICODE && wxUSE_INTL
418    if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 )
419    {
420        // In case we are not using wxLocale to translate strings, convert the
421        // strings GUI's charset. This must not be done when wxXRC_USE_LOCALE
422        // is on, because it could break wxGetTranslation lookup.
423        encoding = wxLocale::GetSystemEncodingName();
424    }
425#endif
426
427    for (size_t i = 0; i < m_data.GetCount(); i++)
428    {
429        modif = (m_data[i].Doc == NULL);
430
431        if (!modif && !(m_flags & wxXRC_NO_RELOADING))
432        {
433#           if wxUSE_FILESYSTEM
434            file = fsys.OpenFile(m_data[i].File);
435#           if wxUSE_DATETIME
436            modif = file && file->GetModificationTime() > m_data[i].Time;
437#           else // wxUSE_DATETIME
438            modif = true;
439#           endif // wxUSE_DATETIME
440            if (!file)
441            {
442                wxLogError(_("Cannot open file '%s'."), m_data[i].File.c_str());
443                rt = false;
444            }
445            wxDELETE(file);
446            wxUnusedVar(file);
447#           else // wxUSE_FILESYSTEM
448#           if wxUSE_DATETIME
449            modif = wxDateTime(wxFileModificationTime(m_data[i].File)) > m_data[i].Time;
450#           else // wxUSE_DATETIME
451            modif = true;
452#           endif // wxUSE_DATETIME
453#           endif // wxUSE_FILESYSTEM
454        }
455
456        if (modif)
457        {
458            wxLogTrace(_T("xrc"),
459                       _T("opening file '%s'"), m_data[i].File.c_str());
460
461            wxInputStream *stream = NULL;
462
463#           if wxUSE_FILESYSTEM
464            file = fsys.OpenFile(m_data[i].File);
465            if (file)
466                stream = file->GetStream();
467#           else
468            stream = new wxFileInputStream(m_data[i].File);
469#           endif
470
471            if (stream)
472            {
473                delete m_data[i].Doc;
474                m_data[i].Doc = new wxXmlDocument;
475            }
476            if (!stream || !m_data[i].Doc->Load(*stream, encoding))
477            {
478                wxLogError(_("Cannot load resources from file '%s'."),
479                           m_data[i].File.c_str());
480                wxDELETE(m_data[i].Doc);
481                rt = false;
482            }
483            else if (m_data[i].Doc->GetRoot()->GetName() != wxT("resource"))
484            {
485                wxLogError(_("Invalid XRC resource '%s': doesn't have root node 'resource'."), m_data[i].File.c_str());
486                wxDELETE(m_data[i].Doc);
487                rt = false;
488            }
489            else
490            {
491                long version;
492                int v1, v2, v3, v4;
493                wxString verstr = m_data[i].Doc->GetRoot()->GetPropVal(
494                                      wxT("version"), wxT("0.0.0.0"));
495                if (wxSscanf(verstr.c_str(), wxT("%i.%i.%i.%i"),
496                    &v1, &v2, &v3, &v4) == 4)
497                    version = v1*256*256*256+v2*256*256+v3*256+v4;
498                else
499                    version = 0;
500                if (m_version == -1)
501                    m_version = version;
502                if (m_version != version)
503                {
504                    wxLogError(_("Resource files must have same version number!"));
505                    rt = false;
506                }
507
508                ProcessPlatformProperty(m_data[i].Doc->GetRoot());
509#if wxUSE_DATETIME
510#if wxUSE_FILESYSTEM
511                m_data[i].Time = file->GetModificationTime();
512#else // wxUSE_FILESYSTEM
513                m_data[i].Time = wxDateTime(wxFileModificationTime(m_data[i].File));
514#endif // wxUSE_FILESYSTEM
515#endif // wxUSE_DATETIME
516            }
517
518#           if wxUSE_FILESYSTEM
519                wxDELETE(file);
520                wxUnusedVar(file);
521#           else
522                wxDELETE(stream);
523#           endif
524        }
525    }
526
527    return rt;
528}
529
530
531wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,
532                                         const wxString& name,
533                                         const wxString& classname,
534                                         bool recursive)
535{
536    wxString dummy;
537    wxXmlNode *node;
538
539    // first search for match at the top-level nodes (as this is
540    // where the resource is most commonly looked for):
541    for (node = parent->GetChildren(); node; node = node->GetNext())
542    {
543        if ( node->GetType() == wxXML_ELEMENT_NODE &&
544                 (node->GetName() == wxT("object") ||
545                  node->GetName() == wxT("object_ref")) &&
546             node->GetPropVal(wxT("name"), &dummy) && dummy == name )
547        {
548            wxString cls(node->GetPropVal(wxT("class"), wxEmptyString));
549            if (!classname || cls == classname)
550                return node;
551            // object_ref may not have 'class' property:
552            if (cls.empty() && node->GetName() == wxT("object_ref"))
553            {
554                wxString refName = node->GetPropVal(wxT("ref"), wxEmptyString);
555                if (refName.empty())
556                    continue;
557                wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
558                if (refNode &&
559                    refNode->GetPropVal(wxT("class"), wxEmptyString) == classname)
560                {
561                    return node;
562                }
563            }
564        }
565    }
566
567    if ( recursive )
568        for (node = parent->GetChildren(); node; node = node->GetNext())
569        {
570            if ( node->GetType() == wxXML_ELEMENT_NODE &&
571                 (node->GetName() == wxT("object") ||
572                  node->GetName() == wxT("object_ref")) )
573            {
574                wxXmlNode* found = DoFindResource(node, name, classname, true);
575                if ( found )
576                    return found;
577            }
578        }
579
580   return NULL;
581}
582
583wxXmlNode *wxXmlResource::FindResource(const wxString& name,
584                                       const wxString& classname,
585                                       bool recursive)
586{
587    UpdateResources(); //ensure everything is up-to-date
588
589    wxString dummy;
590    for (size_t f = 0; f < m_data.GetCount(); f++)
591    {
592        if ( m_data[f].Doc == NULL || m_data[f].Doc->GetRoot() == NULL )
593            continue;
594
595        wxXmlNode* found = DoFindResource(m_data[f].Doc->GetRoot(),
596                                          name, classname, recursive);
597        if ( found )
598        {
599#if wxUSE_FILESYSTEM
600            m_curFileSystem.ChangePathTo(m_data[f].File);
601#endif
602            return found;
603        }
604    }
605
606    wxLogError(_("XRC resource '%s' (class '%s') not found!"),
607               name.c_str(), classname.c_str());
608    return NULL;
609}
610
611static void MergeNodes(wxXmlNode& dest, wxXmlNode& with)
612{
613    // Merge properties:
614    for (wxXmlProperty *prop = with.GetProperties(); prop; prop = prop->GetNext())
615    {
616        wxXmlProperty *dprop;
617        for (dprop = dest.GetProperties(); dprop; dprop = dprop->GetNext())
618        {
619
620            if ( dprop->GetName() == prop->GetName() )
621            {
622                dprop->SetValue(prop->GetValue());
623                break;
624            }
625        }
626
627        if ( !dprop )
628            dest.AddProperty(prop->GetName(), prop->GetValue());
629   }
630
631    // Merge child nodes:
632    for (wxXmlNode* node = with.GetChildren(); node; node = node->GetNext())
633    {
634        wxString name = node->GetPropVal(wxT("name"), wxEmptyString);
635        wxXmlNode *dnode;
636
637        for (dnode = dest.GetChildren(); dnode; dnode = dnode->GetNext() )
638        {
639            if ( dnode->GetName() == node->GetName() &&
640                 dnode->GetPropVal(wxT("name"), wxEmptyString) == name &&
641                 dnode->GetType() == node->GetType() )
642            {
643                MergeNodes(*dnode, *node);
644                break;
645            }
646        }
647
648        if ( !dnode )
649        {
650            static const wxChar *AT_END = wxT("end");
651            wxString insert_pos = node->GetPropVal(wxT("insert_at"), AT_END);
652            if ( insert_pos == AT_END )
653            {
654                dest.AddChild(new wxXmlNode(*node));
655            }
656            else if ( insert_pos == wxT("begin") )
657            {
658                dest.InsertChild(new wxXmlNode(*node), dest.GetChildren());
659            }
660        }
661    }
662
663    if ( dest.GetType() == wxXML_TEXT_NODE && with.GetContent().length() )
664         dest.SetContent(with.GetContent());
665}
666
667wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
668                                           wxObject *instance,
669                                           wxXmlResourceHandler *handlerToUse)
670{
671    if (node == NULL) return NULL;
672
673    // handling of referenced resource
674    if ( node->GetName() == wxT("object_ref") )
675    {
676        wxString refName = node->GetPropVal(wxT("ref"), wxEmptyString);
677        wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
678
679        if ( !refNode )
680        {
681            wxLogError(_("Referenced object node with ref=\"%s\" not found!"),
682                       refName.c_str());
683            return NULL;
684        }
685
686        wxXmlNode copy(*refNode);
687        MergeNodes(copy, *node);
688
689        return CreateResFromNode(&copy, parent, instance);
690    }
691
692    wxXmlResourceHandler *handler;
693
694    if (handlerToUse)
695    {
696        if (handlerToUse->CanHandle(node))
697        {
698            return handlerToUse->CreateResource(node, parent, instance);
699        }
700    }
701    else if (node->GetName() == wxT("object"))
702    {
703        wxList::compatibility_iterator ND = m_handlers.GetFirst();
704        while (ND)
705        {
706            handler = (wxXmlResourceHandler*)ND->GetData();
707            if (handler->CanHandle(node))
708            {
709                return handler->CreateResource(node, parent, instance);
710            }
711            ND = ND->GetNext();
712        }
713    }
714
715    wxLogError(_("No handler found for XML node '%s', class '%s'!"),
716               node->GetName().c_str(),
717               node->GetPropVal(wxT("class"), wxEmptyString).c_str());
718    return NULL;
719}
720
721
722#include "wx/listimpl.cpp"
723WX_DECLARE_LIST(wxXmlSubclassFactory, wxXmlSubclassFactoriesList);
724WX_DEFINE_LIST(wxXmlSubclassFactoriesList)
725
726wxXmlSubclassFactoriesList *wxXmlResource::ms_subclassFactories = NULL;
727
728/*static*/ void wxXmlResource::AddSubclassFactory(wxXmlSubclassFactory *factory)
729{
730    if (!ms_subclassFactories)
731    {
732        ms_subclassFactories = new wxXmlSubclassFactoriesList;
733    }
734    ms_subclassFactories->Append(factory);
735}
736
737class wxXmlSubclassFactoryCXX : public wxXmlSubclassFactory
738{
739public:
740    ~wxXmlSubclassFactoryCXX() {}
741
742    wxObject *Create(const wxString& className)
743    {
744        wxClassInfo* classInfo = wxClassInfo::FindClass(className);
745
746        if (classInfo)
747            return classInfo->CreateObject();
748        else
749            return NULL;
750    }
751};
752
753
754
755
756wxXmlResourceHandler::wxXmlResourceHandler()
757        : m_node(NULL), m_parent(NULL), m_instance(NULL),
758          m_parentAsWindow(NULL)
759{}
760
761
762
763wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance)
764{
765    wxXmlNode *myNode = m_node;
766    wxString myClass = m_class;
767    wxObject *myParent = m_parent, *myInstance = m_instance;
768    wxWindow *myParentAW = m_parentAsWindow;
769
770    m_instance = instance;
771    if (!m_instance && node->HasProp(wxT("subclass")) &&
772        !(m_resource->GetFlags() & wxXRC_NO_SUBCLASSING))
773    {
774        wxString subclass = node->GetPropVal(wxT("subclass"), wxEmptyString);
775        if (!subclass.empty())
776        {
777            for (wxXmlSubclassFactoriesList::compatibility_iterator i = wxXmlResource::ms_subclassFactories->GetFirst();
778                 i; i = i->GetNext())
779            {
780                m_instance = i->GetData()->Create(subclass);
781                if (m_instance)
782                    break;
783            }
784
785            if (!m_instance)
786            {
787                wxString name = node->GetPropVal(wxT("name"), wxEmptyString);
788                wxLogError(_("Subclass '%s' not found for resource '%s', not subclassing!"),
789                           subclass.c_str(), name.c_str());
790            }
791        }
792    }
793
794    m_node = node;
795    m_class = node->GetPropVal(wxT("class"), wxEmptyString);
796    m_parent = parent;
797    m_parentAsWindow = wxDynamicCast(m_parent, wxWindow);
798
799    wxObject *returned = DoCreateResource();
800
801    m_node = myNode;
802    m_class = myClass;
803    m_parent = myParent; m_parentAsWindow = myParentAW;
804    m_instance = myInstance;
805
806    return returned;
807}
808
809
810void wxXmlResourceHandler::AddStyle(const wxString& name, int value)
811{
812    m_styleNames.Add(name);
813    m_styleValues.Add(value);
814}
815
816
817
818void wxXmlResourceHandler::AddWindowStyles()
819{
820    XRC_ADD_STYLE(wxCLIP_CHILDREN);
821
822    // the border styles all have the old and new names, recognize both for now
823    XRC_ADD_STYLE(wxSIMPLE_BORDER); XRC_ADD_STYLE(wxBORDER_SIMPLE);
824    XRC_ADD_STYLE(wxSUNKEN_BORDER); XRC_ADD_STYLE(wxBORDER_SUNKEN);
825    XRC_ADD_STYLE(wxDOUBLE_BORDER); XRC_ADD_STYLE(wxBORDER_DOUBLE); // deprecated
826    XRC_ADD_STYLE(wxBORDER_THEME);
827    XRC_ADD_STYLE(wxRAISED_BORDER); XRC_ADD_STYLE(wxBORDER_RAISED);
828    XRC_ADD_STYLE(wxSTATIC_BORDER); XRC_ADD_STYLE(wxBORDER_STATIC);
829    XRC_ADD_STYLE(wxNO_BORDER);     XRC_ADD_STYLE(wxBORDER_NONE);
830
831    XRC_ADD_STYLE(wxTRANSPARENT_WINDOW);
832    XRC_ADD_STYLE(wxWANTS_CHARS);
833    XRC_ADD_STYLE(wxTAB_TRAVERSAL);
834    XRC_ADD_STYLE(wxNO_FULL_REPAINT_ON_RESIZE);
835    XRC_ADD_STYLE(wxFULL_REPAINT_ON_RESIZE);
836    XRC_ADD_STYLE(wxALWAYS_SHOW_SB);
837    XRC_ADD_STYLE(wxWS_EX_BLOCK_EVENTS);
838    XRC_ADD_STYLE(wxWS_EX_VALIDATE_RECURSIVELY);
839}
840
841
842
843bool wxXmlResourceHandler::HasParam(const wxString& param)
844{
845    return (GetParamNode(param) != NULL);
846}
847
848
849int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
850{
851    wxString s = GetParamValue(param);
852
853    if (!s) return defaults;
854
855    wxStringTokenizer tkn(s, wxT("| \t\n"), wxTOKEN_STRTOK);
856    int style = 0;
857    int index;
858    wxString fl;
859    while (tkn.HasMoreTokens())
860    {
861        fl = tkn.GetNextToken();
862        index = m_styleNames.Index(fl);
863        if (index != wxNOT_FOUND)
864            style |= m_styleValues[index];
865        else
866            wxLogError(_("Unknown style flag ") + fl);
867    }
868    return style;
869}
870
871
872
873wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate)
874{
875    wxXmlNode *parNode = GetParamNode(param);
876    wxString str1(GetNodeContent(parNode));
877    wxString str2;
878    const wxChar *dt;
879    wxChar amp_char;
880
881    // VS: First version of XRC resources used $ instead of & (which is
882    //     illegal in XML), but later I realized that '_' fits this purpose
883    //     much better (because &File means "File with F underlined").
884    if (m_resource->CompareVersion(2,3,0,1) < 0)
885        amp_char = wxT('$');
886    else
887        amp_char = wxT('_');
888
889    for (dt = str1.c_str(); *dt; dt++)
890    {
891        // Remap amp_char to &, map double amp_char to amp_char (for things
892        // like "&File..." -- this is illegal in XML, so we use "_File..."):
893        if (*dt == amp_char)
894        {
895            if ( *(++dt) == amp_char )
896                str2 << amp_char;
897            else
898                str2 << wxT('&') << *dt;
899        }
900        // Remap \n to CR, \r to LF, \t to TAB, \\ to \:
901        else if (*dt == wxT('\\'))
902            switch (*(++dt))
903            {
904                case wxT('n'):
905                    str2 << wxT('\n');
906                    break;
907
908                case wxT('t'):
909                    str2 << wxT('\t');
910                    break;
911
912                case wxT('r'):
913                    str2 << wxT('\r');
914                    break;
915
916                case wxT('\\') :
917                    // "\\" wasn't translated to "\" prior to 2.5.3.0:
918                    if (m_resource->CompareVersion(2,5,3,0) >= 0)
919                    {
920                        str2 << wxT('\\');
921                        break;
922                    }
923                    // else fall-through to default: branch below
924
925                default:
926                    str2 << wxT('\\') << *dt;
927                    break;
928            }
929        else str2 << *dt;
930    }
931
932    if (m_resource->GetFlags() & wxXRC_USE_LOCALE)
933    {
934        if (translate && parNode &&
935            parNode->GetPropVal(wxT("translate"), wxEmptyString) != wxT("0"))
936        {
937            return wxGetTranslation(str2, m_resource->GetDomain());
938        }
939        else
940        {
941#if wxUSE_UNICODE
942            return str2;
943#else
944            // The string is internally stored as UTF-8, we have to convert
945            // it into system's default encoding so that it can be displayed:
946            return wxString(str2.wc_str(wxConvUTF8), wxConvLocal);
947#endif
948        }
949    }
950
951    // If wxXRC_USE_LOCALE is not set, then the string is already in
952    // system's default encoding in ANSI build, so we don't have to
953    // do anything special here.
954    return str2;
955}
956
957
958
959long wxXmlResourceHandler::GetLong(const wxString& param, long defaultv)
960{
961    long value;
962    wxString str1 = GetParamValue(param);
963
964    if (!str1.ToLong(&value))
965        value = defaultv;
966
967    return value;
968}
969
970float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv)
971{
972    wxString str = GetParamValue(param);
973
974#if wxUSE_INTL
975    // strings in XRC always use C locale but wxString::ToDouble() uses the
976    // current one, so transform the string to it supposing that the only
977    // difference between them is the decimal separator
978    str.Replace(wxT("."), wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
979                                            wxLOCALE_CAT_NUMBER));
980#endif // wxUSE_INTL
981
982    double value;
983    if (!str.ToDouble(&value))
984        value = defaultv;
985
986    return wx_truncate_cast(float, value);
987}
988
989
990int wxXmlResourceHandler::GetID()
991{
992    return wxXmlResource::GetXRCID(GetName());
993}
994
995
996
997wxString wxXmlResourceHandler::GetName()
998{
999    return m_node->GetPropVal(wxT("name"), wxT("-1"));
1000}
1001
1002
1003
1004bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv)
1005{
1006    wxString v = GetParamValue(param);
1007    v.MakeLower();
1008    if (!v) return defaultv;
1009
1010    return (v == wxT("1"));
1011}
1012
1013
1014static wxColour GetSystemColour(const wxString& name)
1015{
1016    if (!name.empty())
1017    {
1018        #define SYSCLR(clr) \
1019            if (name == _T(#clr)) return wxSystemSettings::GetColour(clr);
1020        SYSCLR(wxSYS_COLOUR_SCROLLBAR)
1021        SYSCLR(wxSYS_COLOUR_BACKGROUND)
1022        SYSCLR(wxSYS_COLOUR_DESKTOP)
1023        SYSCLR(wxSYS_COLOUR_ACTIVECAPTION)
1024        SYSCLR(wxSYS_COLOUR_INACTIVECAPTION)
1025        SYSCLR(wxSYS_COLOUR_MENU)
1026        SYSCLR(wxSYS_COLOUR_WINDOW)
1027        SYSCLR(wxSYS_COLOUR_WINDOWFRAME)
1028        SYSCLR(wxSYS_COLOUR_MENUTEXT)
1029        SYSCLR(wxSYS_COLOUR_WINDOWTEXT)
1030        SYSCLR(wxSYS_COLOUR_CAPTIONTEXT)
1031        SYSCLR(wxSYS_COLOUR_ACTIVEBORDER)
1032        SYSCLR(wxSYS_COLOUR_INACTIVEBORDER)
1033        SYSCLR(wxSYS_COLOUR_APPWORKSPACE)
1034        SYSCLR(wxSYS_COLOUR_HIGHLIGHT)
1035        SYSCLR(wxSYS_COLOUR_HIGHLIGHTTEXT)
1036        SYSCLR(wxSYS_COLOUR_BTNFACE)
1037        SYSCLR(wxSYS_COLOUR_3DFACE)
1038        SYSCLR(wxSYS_COLOUR_BTNSHADOW)
1039        SYSCLR(wxSYS_COLOUR_3DSHADOW)
1040        SYSCLR(wxSYS_COLOUR_GRAYTEXT)
1041        SYSCLR(wxSYS_COLOUR_BTNTEXT)
1042        SYSCLR(wxSYS_COLOUR_INACTIVECAPTIONTEXT)
1043        SYSCLR(wxSYS_COLOUR_BTNHIGHLIGHT)
1044        SYSCLR(wxSYS_COLOUR_BTNHILIGHT)
1045        SYSCLR(wxSYS_COLOUR_3DHIGHLIGHT)
1046        SYSCLR(wxSYS_COLOUR_3DHILIGHT)
1047        SYSCLR(wxSYS_COLOUR_3DDKSHADOW)
1048        SYSCLR(wxSYS_COLOUR_3DLIGHT)
1049        SYSCLR(wxSYS_COLOUR_INFOTEXT)
1050        SYSCLR(wxSYS_COLOUR_INFOBK)
1051        SYSCLR(wxSYS_COLOUR_LISTBOX)
1052        SYSCLR(wxSYS_COLOUR_HOTLIGHT)
1053        SYSCLR(wxSYS_COLOUR_GRADIENTACTIVECAPTION)
1054        SYSCLR(wxSYS_COLOUR_GRADIENTINACTIVECAPTION)
1055        SYSCLR(wxSYS_COLOUR_MENUHILIGHT)
1056        SYSCLR(wxSYS_COLOUR_MENUBAR)
1057        #undef SYSCLR
1058    }
1059
1060    return wxNullColour;
1061}
1062
1063wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& defaultv)
1064{
1065    wxString v = GetParamValue(param);
1066
1067    if ( v.empty() )
1068        return defaultv;
1069
1070    wxColour clr;
1071
1072    // wxString -> wxColour conversion
1073    if (!clr.Set(v))
1074    {
1075        // the colour doesn't use #RRGGBB format, check if it is symbolic
1076        // colour name:
1077        clr = GetSystemColour(v);
1078        if (clr.Ok())
1079            return clr;
1080
1081        wxLogError(_("XRC resource: Incorrect colour specification '%s' for property '%s'."),
1082                   v.c_str(), param.c_str());
1083        return wxNullColour;
1084    }
1085
1086    return clr;
1087}
1088
1089
1090
1091wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
1092                                         const wxArtClient& defaultArtClient,
1093                                         wxSize size)
1094{
1095    /* If the bitmap is specified as stock item, query wxArtProvider for it: */
1096    wxXmlNode *bmpNode = GetParamNode(param);
1097    if ( bmpNode )
1098    {
1099        wxString sid = bmpNode->GetPropVal(wxT("stock_id"), wxEmptyString);
1100        if ( !sid.empty() )
1101        {
1102            wxString scl = bmpNode->GetPropVal(wxT("stock_client"), wxEmptyString);
1103            if (scl.empty())
1104                scl = defaultArtClient;
1105            else
1106                scl = wxART_MAKE_CLIENT_ID_FROM_STR(scl);
1107
1108            wxBitmap stockArt =
1109                wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(sid),
1110                                         scl, size);
1111            if ( stockArt.Ok() )
1112                return stockArt;
1113        }
1114    }
1115
1116    /* ...or load the bitmap from file: */
1117    wxString name = GetParamValue(param);
1118    if (name.empty()) return wxNullBitmap;
1119#if wxUSE_FILESYSTEM
1120    wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
1121    if (fsfile == NULL)
1122    {
1123        wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
1124                   name.c_str());
1125        return wxNullBitmap;
1126    }
1127    wxImage img(*(fsfile->GetStream()));
1128    delete fsfile;
1129#else
1130    wxImage img(name);
1131#endif
1132
1133    if (!img.Ok())
1134    {
1135        wxLogError(_("XRC resource: Cannot create bitmap from '%s'."),
1136                   name.c_str());
1137        return wxNullBitmap;
1138    }
1139    if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
1140    return wxBitmap(img);
1141}
1142
1143#if wxUSE_ANIMATIONCTRL
1144wxAnimation wxXmlResourceHandler::GetAnimation(const wxString& param)
1145{
1146    wxAnimation ani;
1147
1148    /* load the animation from file: */
1149    wxString name = GetParamValue(param);
1150    if (name.empty()) return wxNullAnimation;
1151#if wxUSE_FILESYSTEM
1152    wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
1153    if (fsfile == NULL)
1154    {
1155        wxLogError(_("XRC resource: Cannot create animation from '%s'."),
1156                   name.c_str());
1157        return wxNullAnimation;
1158    }
1159    ani.Load(*(fsfile->GetStream()));
1160    delete fsfile;
1161#else
1162    ani.LoadFile(name);
1163#endif
1164
1165    if (!ani.IsOk())
1166    {
1167        wxLogError(_("XRC resource: Cannot create animation from '%s'."),
1168                   name.c_str());
1169        return wxNullAnimation;
1170    }
1171
1172    return ani;
1173}
1174#endif      // wxUSE_ANIMATIONCTRL
1175
1176
1177
1178wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
1179                                     const wxArtClient& defaultArtClient,
1180                                     wxSize size)
1181{
1182    wxIcon icon;
1183    icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size));
1184    return icon;
1185}
1186
1187
1188
1189wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
1190{
1191    wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!"));
1192
1193    wxXmlNode *n = m_node->GetChildren();
1194
1195    while (n)
1196    {
1197        if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
1198            return n;
1199        n = n->GetNext();
1200    }
1201    return NULL;
1202}
1203
1204
1205
1206bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
1207{
1208    return node->GetPropVal(wxT("class"), wxEmptyString) == classname;
1209}
1210
1211
1212
1213wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
1214{
1215    wxXmlNode *n = node;
1216    if (n == NULL) return wxEmptyString;
1217    n = n->GetChildren();
1218
1219    while (n)
1220    {
1221        if (n->GetType() == wxXML_TEXT_NODE ||
1222            n->GetType() == wxXML_CDATA_SECTION_NODE)
1223            return n->GetContent();
1224        n = n->GetNext();
1225    }
1226    return wxEmptyString;
1227}
1228
1229
1230
1231wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
1232{
1233    if (param.empty())
1234        return GetNodeContent(m_node);
1235    else
1236        return GetNodeContent(GetParamNode(param));
1237}
1238
1239
1240
1241wxSize wxXmlResourceHandler::GetSize(const wxString& param,
1242                                     wxWindow *windowToUse)
1243{
1244    wxString s = GetParamValue(param);
1245    if (s.empty()) s = wxT("-1,-1");
1246    bool is_dlg;
1247    long sx, sy = 0;
1248
1249    is_dlg = s[s.length()-1] == wxT('d');
1250    if (is_dlg) s.RemoveLast();
1251
1252    if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
1253        !s.AfterLast(wxT(',')).ToLong(&sy))
1254    {
1255        wxLogError(_("Cannot parse coordinates from '%s'."), s.c_str());
1256        return wxDefaultSize;
1257    }
1258
1259    if (is_dlg)
1260    {
1261        if (windowToUse)
1262        {
1263            return wxDLG_UNIT(windowToUse, wxSize(sx, sy));
1264        }
1265        else if (m_parentAsWindow)
1266        {
1267            return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, sy));
1268        }
1269        else
1270        {
1271            wxLogError(_("Cannot convert dialog units: dialog unknown."));
1272            return wxDefaultSize;
1273        }
1274    }
1275
1276    return wxSize(sx, sy);
1277}
1278
1279
1280
1281wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
1282{
1283    wxSize sz = GetSize(param);
1284    return wxPoint(sz.x, sz.y);
1285}
1286
1287
1288
1289wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
1290                                           wxCoord defaultv,
1291                                           wxWindow *windowToUse)
1292{
1293    wxString s = GetParamValue(param);
1294    if (s.empty()) return defaultv;
1295    bool is_dlg;
1296    long sx;
1297
1298    is_dlg = s[s.length()-1] == wxT('d');
1299    if (is_dlg) s.RemoveLast();
1300
1301    if (!s.ToLong(&sx))
1302    {
1303        wxLogError(_("Cannot parse dimension from '%s'."), s.c_str());
1304        return defaultv;
1305    }
1306
1307    if (is_dlg)
1308    {
1309        if (windowToUse)
1310        {
1311            return wxDLG_UNIT(windowToUse, wxSize(sx, 0)).x;
1312        }
1313        else if (m_parentAsWindow)
1314        {
1315            return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, 0)).x;
1316        }
1317        else
1318        {
1319            wxLogError(_("Cannot convert dialog units: dialog unknown."));
1320            return defaultv;
1321        }
1322    }
1323
1324    return sx;
1325}
1326
1327
1328// Get system font index using indexname
1329static wxFont GetSystemFont(const wxString& name)
1330{
1331    if (!name.empty())
1332    {
1333        #define SYSFNT(fnt) \
1334            if (name == _T(#fnt)) return wxSystemSettings::GetFont(fnt);
1335        SYSFNT(wxSYS_OEM_FIXED_FONT)
1336        SYSFNT(wxSYS_ANSI_FIXED_FONT)
1337        SYSFNT(wxSYS_ANSI_VAR_FONT)
1338        SYSFNT(wxSYS_SYSTEM_FONT)
1339        SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
1340        SYSFNT(wxSYS_DEFAULT_PALETTE)
1341        SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
1342        SYSFNT(wxSYS_DEFAULT_GUI_FONT)
1343        #undef SYSFNT
1344    }
1345
1346    return wxNullFont;
1347}
1348
1349wxFont wxXmlResourceHandler::GetFont(const wxString& param)
1350{
1351    wxXmlNode *font_node = GetParamNode(param);
1352    if (font_node == NULL)
1353    {
1354        wxLogError(_("Cannot find font node '%s'."), param.c_str());
1355        return wxNullFont;
1356    }
1357
1358    wxXmlNode *oldnode = m_node;
1359    m_node = font_node;
1360
1361    // font attributes:
1362
1363    // size
1364    int isize = -1;
1365    bool hasSize = HasParam(wxT("size"));
1366    if (hasSize)
1367        isize = GetLong(wxT("size"), -1);
1368
1369    // style
1370    int istyle = wxNORMAL;
1371    bool hasStyle = HasParam(wxT("style"));
1372    if (hasStyle)
1373    {
1374        wxString style = GetParamValue(wxT("style"));
1375        if (style == wxT("italic"))
1376            istyle = wxITALIC;
1377        else if (style == wxT("slant"))
1378            istyle = wxSLANT;
1379    }
1380
1381    // weight
1382    int iweight = wxNORMAL;
1383    bool hasWeight = HasParam(wxT("weight"));
1384    if (hasWeight)
1385    {
1386        wxString weight = GetParamValue(wxT("weight"));
1387        if (weight == wxT("bold"))
1388            iweight = wxBOLD;
1389        else if (weight == wxT("light"))
1390            iweight = wxLIGHT;
1391    }
1392
1393    // underline
1394    bool hasUnderlined = HasParam(wxT("underlined"));
1395    bool underlined = hasUnderlined ? GetBool(wxT("underlined"), false) : false;
1396
1397    // family and facename
1398    int ifamily = wxDEFAULT;
1399    bool hasFamily = HasParam(wxT("family"));
1400    if (hasFamily)
1401    {
1402        wxString family = GetParamValue(wxT("family"));
1403             if (family == wxT("decorative")) ifamily = wxDECORATIVE;
1404        else if (family == wxT("roman")) ifamily = wxROMAN;
1405        else if (family == wxT("script")) ifamily = wxSCRIPT;
1406        else if (family == wxT("swiss")) ifamily = wxSWISS;
1407        else if (family == wxT("modern")) ifamily = wxMODERN;
1408        else if (family == wxT("teletype")) ifamily = wxTELETYPE;
1409    }
1410
1411
1412    wxString facename;
1413    bool hasFacename = HasParam(wxT("face"));
1414    if (hasFacename)
1415    {
1416        wxString faces = GetParamValue(wxT("face"));
1417        wxArrayString facenames(wxFontEnumerator::GetFacenames());
1418        wxStringTokenizer tk(faces, wxT(","));
1419        while (tk.HasMoreTokens())
1420        {
1421            int index = facenames.Index(tk.GetNextToken(), false);
1422            if (index != wxNOT_FOUND)
1423            {
1424                facename = facenames[index];
1425                break;
1426            }
1427        }
1428    }
1429
1430    // encoding
1431    wxFontEncoding enc = wxFONTENCODING_DEFAULT;
1432    bool hasEncoding = HasParam(wxT("encoding"));
1433    if (hasEncoding)
1434    {
1435        wxString encoding = GetParamValue(wxT("encoding"));
1436        wxFontMapper mapper;
1437        if (!encoding.empty())
1438            enc = mapper.CharsetToEncoding(encoding);
1439        if (enc == wxFONTENCODING_SYSTEM)
1440            enc = wxFONTENCODING_DEFAULT;
1441    }
1442
1443    // is this font based on a system font?
1444    wxFont font = GetSystemFont(GetParamValue(wxT("sysfont")));
1445
1446    if (font.Ok())
1447    {
1448        if (hasSize && isize != -1)
1449            font.SetPointSize(isize);
1450        else if (HasParam(wxT("relativesize")))
1451            font.SetPointSize(int(font.GetPointSize() *
1452                                     GetFloat(wxT("relativesize"))));
1453
1454        if (hasStyle)
1455            font.SetStyle(istyle);
1456        if (hasWeight)
1457            font.SetWeight(iweight);
1458        if (hasUnderlined)
1459            font.SetUnderlined(underlined);
1460        if (hasFamily)
1461            font.SetFamily(ifamily);
1462        if (hasFacename)
1463            font.SetFaceName(facename);
1464        if (hasEncoding)
1465            font.SetDefaultEncoding(enc);
1466    }
1467    else // not based on system font
1468    {
1469        font = wxFont(isize == -1 ? wxNORMAL_FONT->GetPointSize() : isize,
1470                      ifamily, istyle, iweight,
1471                      underlined, facename, enc);
1472    }
1473
1474    m_node = oldnode;
1475    return font;
1476}
1477
1478
1479void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
1480{
1481    //FIXME : add cursor
1482
1483    if (HasParam(wxT("exstyle")))
1484        // Have to OR it with existing style, since
1485        // some implementations (e.g. wxGTK) use the extra style
1486        // during creation
1487        wnd->SetExtraStyle(wnd->GetExtraStyle() | GetStyle(wxT("exstyle")));
1488    if (HasParam(wxT("bg")))
1489        wnd->SetBackgroundColour(GetColour(wxT("bg")));
1490    if (HasParam(wxT("fg")))
1491        wnd->SetForegroundColour(GetColour(wxT("fg")));
1492    if (GetBool(wxT("enabled"), 1) == 0)
1493        wnd->Enable(false);
1494    if (GetBool(wxT("focused"), 0) == 1)
1495        wnd->SetFocus();
1496    if (GetBool(wxT("hidden"), 0) == 1)
1497        wnd->Show(false);
1498#if wxUSE_TOOLTIPS
1499    if (HasParam(wxT("tooltip")))
1500        wnd->SetToolTip(GetText(wxT("tooltip")));
1501#endif
1502    if (HasParam(wxT("font")))
1503        wnd->SetFont(GetFont());
1504    if (HasParam(wxT("help")))
1505        wnd->SetHelpText(GetText(wxT("help")));
1506}
1507
1508
1509void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
1510{
1511    wxXmlNode *n = m_node->GetChildren();
1512
1513    while (n)
1514    {
1515        if (n->GetType() == wxXML_ELEMENT_NODE &&
1516           (n->GetName() == wxT("object") || n->GetName() == wxT("object_ref")))
1517        {
1518            m_resource->CreateResFromNode(n, parent, NULL,
1519                                          this_hnd_only ? this : NULL);
1520        }
1521        n = n->GetNext();
1522    }
1523}
1524
1525
1526void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode)
1527{
1528    wxXmlNode *root;
1529    if (rootnode == NULL) root = m_node; else root = rootnode;
1530    wxXmlNode *n = root->GetChildren();
1531
1532    while (n)
1533    {
1534        if (n->GetType() == wxXML_ELEMENT_NODE && CanHandle(n))
1535        {
1536            CreateResource(n, parent, NULL);
1537        }
1538        n = n->GetNext();
1539    }
1540}
1541
1542
1543
1544
1545
1546
1547
1548// --------------- XRCID implementation -----------------------------
1549
1550#define XRCID_TABLE_SIZE     1024
1551
1552
1553struct XRCID_record
1554{
1555    int id;
1556    wxChar *key;
1557    XRCID_record *next;
1558};
1559
1560static XRCID_record *XRCID_Records[XRCID_TABLE_SIZE] = {NULL};
1561
1562static int XRCID_Lookup(const wxChar *str_id, int value_if_not_found = wxID_NONE)
1563{
1564    unsigned int index = 0;
1565
1566    for (const wxChar *c = str_id; *c != wxT('\0'); c++) index += (unsigned int)*c;
1567    index %= XRCID_TABLE_SIZE;
1568
1569    XRCID_record *oldrec = NULL;
1570    for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
1571    {
1572        if (wxStrcmp(rec->key, str_id) == 0)
1573        {
1574            return rec->id;
1575        }
1576        oldrec = rec;
1577    }
1578
1579    XRCID_record **rec_var = (oldrec == NULL) ?
1580                              &XRCID_Records[index] : &oldrec->next;
1581    *rec_var = new XRCID_record;
1582    (*rec_var)->key = wxStrdup(str_id);
1583    (*rec_var)->next = NULL;
1584
1585    wxChar *end;
1586    if (value_if_not_found != wxID_NONE)
1587        (*rec_var)->id = value_if_not_found;
1588    else
1589    {
1590        int asint = wxStrtol(str_id, &end, 10);
1591        if (*str_id && *end == 0)
1592        {
1593            // if str_id was integer, keep it verbosely:
1594            (*rec_var)->id = asint;
1595        }
1596        else
1597        {
1598            (*rec_var)->id = wxNewId();
1599        }
1600    }
1601
1602    return (*rec_var)->id;
1603}
1604
1605static void AddStdXRCID_Records();
1606
1607/*static*/
1608int wxXmlResource::GetXRCID(const wxChar *str_id, int value_if_not_found)
1609{
1610    static bool s_stdIDsAdded = false;
1611
1612    if ( !s_stdIDsAdded )
1613    {
1614        s_stdIDsAdded = true;
1615        AddStdXRCID_Records();
1616    }
1617
1618    return XRCID_Lookup(str_id, value_if_not_found);
1619}
1620
1621
1622static void CleanXRCID_Record(XRCID_record *rec)
1623{
1624    if (rec)
1625    {
1626        CleanXRCID_Record(rec->next);
1627        free(rec->key);
1628        delete rec;
1629    }
1630}
1631
1632static void CleanXRCID_Records()
1633{
1634    for (int i = 0; i < XRCID_TABLE_SIZE; i++)
1635    {
1636        CleanXRCID_Record(XRCID_Records[i]);
1637        XRCID_Records[i] = NULL;
1638    }
1639}
1640
1641static void AddStdXRCID_Records()
1642{
1643#define stdID(id) XRCID_Lookup(wxT(#id), id)
1644    stdID(-1);
1645
1646    stdID(wxID_ANY);
1647    stdID(wxID_SEPARATOR);
1648
1649    stdID(wxID_OPEN);
1650    stdID(wxID_CLOSE);
1651    stdID(wxID_NEW);
1652    stdID(wxID_SAVE);
1653    stdID(wxID_SAVEAS);
1654    stdID(wxID_REVERT);
1655    stdID(wxID_EXIT);
1656    stdID(wxID_UNDO);
1657    stdID(wxID_REDO);
1658    stdID(wxID_HELP);
1659    stdID(wxID_PRINT);
1660    stdID(wxID_PRINT_SETUP);
1661    stdID(wxID_PAGE_SETUP);
1662    stdID(wxID_PREVIEW);
1663    stdID(wxID_ABOUT);
1664    stdID(wxID_HELP_CONTENTS);
1665    stdID(wxID_HELP_COMMANDS);
1666    stdID(wxID_HELP_PROCEDURES);
1667    stdID(wxID_HELP_CONTEXT);
1668    stdID(wxID_CLOSE_ALL);
1669    stdID(wxID_PREFERENCES);
1670    stdID(wxID_EDIT);
1671    stdID(wxID_CUT);
1672    stdID(wxID_COPY);
1673    stdID(wxID_PASTE);
1674    stdID(wxID_CLEAR);
1675    stdID(wxID_FIND);
1676    stdID(wxID_DUPLICATE);
1677    stdID(wxID_SELECTALL);
1678    stdID(wxID_DELETE);
1679    stdID(wxID_REPLACE);
1680    stdID(wxID_REPLACE_ALL);
1681    stdID(wxID_PROPERTIES);
1682    stdID(wxID_VIEW_DETAILS);
1683    stdID(wxID_VIEW_LARGEICONS);
1684    stdID(wxID_VIEW_SMALLICONS);
1685    stdID(wxID_VIEW_LIST);
1686    stdID(wxID_VIEW_SORTDATE);
1687    stdID(wxID_VIEW_SORTNAME);
1688    stdID(wxID_VIEW_SORTSIZE);
1689    stdID(wxID_VIEW_SORTTYPE);
1690    stdID(wxID_FILE1);
1691    stdID(wxID_FILE2);
1692    stdID(wxID_FILE3);
1693    stdID(wxID_FILE4);
1694    stdID(wxID_FILE5);
1695    stdID(wxID_FILE6);
1696    stdID(wxID_FILE7);
1697    stdID(wxID_FILE8);
1698    stdID(wxID_FILE9);
1699    stdID(wxID_OK);
1700    stdID(wxID_CANCEL);
1701    stdID(wxID_APPLY);
1702    stdID(wxID_YES);
1703    stdID(wxID_NO);
1704    stdID(wxID_STATIC);
1705    stdID(wxID_FORWARD);
1706    stdID(wxID_BACKWARD);
1707    stdID(wxID_DEFAULT);
1708    stdID(wxID_MORE);
1709    stdID(wxID_SETUP);
1710    stdID(wxID_RESET);
1711    stdID(wxID_CONTEXT_HELP);
1712    stdID(wxID_YESTOALL);
1713    stdID(wxID_NOTOALL);
1714    stdID(wxID_ABORT);
1715    stdID(wxID_RETRY);
1716    stdID(wxID_IGNORE);
1717    stdID(wxID_ADD);
1718    stdID(wxID_REMOVE);
1719    stdID(wxID_UP);
1720    stdID(wxID_DOWN);
1721    stdID(wxID_HOME);
1722    stdID(wxID_REFRESH);
1723    stdID(wxID_STOP);
1724    stdID(wxID_INDEX);
1725    stdID(wxID_BOLD);
1726    stdID(wxID_ITALIC);
1727    stdID(wxID_JUSTIFY_CENTER);
1728    stdID(wxID_JUSTIFY_FILL);
1729    stdID(wxID_JUSTIFY_RIGHT);
1730    stdID(wxID_JUSTIFY_LEFT);
1731    stdID(wxID_UNDERLINE);
1732    stdID(wxID_INDENT);
1733    stdID(wxID_UNINDENT);
1734    stdID(wxID_ZOOM_100);
1735    stdID(wxID_ZOOM_FIT);
1736    stdID(wxID_ZOOM_IN);
1737    stdID(wxID_ZOOM_OUT);
1738    stdID(wxID_UNDELETE);
1739    stdID(wxID_REVERT_TO_SAVED);
1740    stdID(wxID_SYSTEM_MENU);
1741    stdID(wxID_CLOSE_FRAME);
1742    stdID(wxID_MOVE_FRAME);
1743    stdID(wxID_RESIZE_FRAME);
1744    stdID(wxID_MAXIMIZE_FRAME);
1745    stdID(wxID_ICONIZE_FRAME);
1746    stdID(wxID_RESTORE_FRAME);
1747
1748#undef stdID
1749}
1750
1751
1752
1753
1754
1755// --------------- module and globals -----------------------------
1756
1757class wxXmlResourceModule: public wxModule
1758{
1759DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
1760public:
1761    wxXmlResourceModule() {}
1762    bool OnInit()
1763    {
1764        wxXmlResource::AddSubclassFactory(new wxXmlSubclassFactoryCXX);
1765        return true;
1766    }
1767    void OnExit()
1768    {
1769        delete wxXmlResource::Set(NULL);
1770        if(wxXmlResource::ms_subclassFactories)
1771            WX_CLEAR_LIST(wxXmlSubclassFactoriesList, *wxXmlResource::ms_subclassFactories);
1772        wxDELETE(wxXmlResource::ms_subclassFactories);
1773        CleanXRCID_Records();
1774    }
1775};
1776
1777IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)
1778
1779
1780// When wxXml is loaded dynamically after the application is already running
1781// then the built-in module system won't pick this one up.  Add it manually.
1782void wxXmlInitResourceModule()
1783{
1784    wxModule* module = new wxXmlResourceModule;
1785    module->Init();
1786    wxModule::RegisterModule(module);
1787}
1788
1789#endif // wxUSE_XRC
1790