]> git.saurik.com Git - wxWidgets.git/blame - src/xrc/xmlres.cpp
Fixed bug: wxPropertyGridInterface::SetPropertyReadOnly() with wxPG_DONT_RECURSE...
[wxWidgets.git] / src / xrc / xmlres.cpp
CommitLineData
78d14f80 1/////////////////////////////////////////////////////////////////////////////
88a7a4e1 2// Name: src/xrc/xmlres.cpp
b5d6954b 3// Purpose: XRC resources
78d14f80
VS
4// Author: Vaclav Slavik
5// Created: 2000/03/05
6// RCS-ID: $Id$
7// Copyright: (c) 2000 Vaclav Slavik
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
78d14f80
VS
11// For compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
621be1ec 18#if wxUSE_XRC
a1e4ec87 19
88a7a4e1
WS
20#include "wx/xrc/xmlres.h"
21
22#ifndef WX_PRECOMP
23 #include "wx/intl.h"
e4db172a 24 #include "wx/log.h"
8e609c82 25 #include "wx/panel.h"
76b49cf4 26 #include "wx/frame.h"
fdf565fe 27 #include "wx/dialog.h"
9eddec69 28 #include "wx/settings.h"
0bca0373 29 #include "wx/bitmap.h"
155ecd4c 30 #include "wx/image.h"
02761f6c 31 #include "wx/module.h"
193d0c93 32 #include "wx/wxcrtvararg.h"
88a7a4e1
WS
33#endif
34
e7a3a5a5 35#ifndef __WXWINCE__
88a7a4e1 36 #include <locale.h>
e7a3a5a5 37#endif
1df61962 38
eb2d0d23 39#include "wx/vector.h"
78d14f80
VS
40#include "wx/wfstream.h"
41#include "wx/filesys.h"
317a0d73 42#include "wx/filename.h"
78d14f80
VS
43#include "wx/tokenzr.h"
44#include "wx/fontenum.h"
78d14f80 45#include "wx/fontmap.h"
af1337b0 46#include "wx/artprov.h"
2bb9a404 47#include "wx/dir.h"
34c6bbee 48#include "wx/xml/xml.h"
78d14f80 49
f35fdf7e 50
eb2d0d23
VS
51class wxXmlResourceDataRecord
52{
53public:
54 wxXmlResourceDataRecord() : Doc(NULL) {
55#if wxUSE_DATETIME
56 Time = wxDateTime::Now();
57#endif
58 }
59 ~wxXmlResourceDataRecord() {delete Doc;}
60
61 wxString File;
62 wxXmlDocument *Doc;
63#if wxUSE_DATETIME
64 wxDateTime Time;
65#endif
66};
67
f396e5a7 68class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord*>
eb2d0d23
VS
69{
70 // this is a class so that it can be forward-declared
71};
78d14f80 72
23239d94
VZ
73namespace
74{
75
76// helper used by DoFindResource() and elsewhere: returns true if this is an
77// object or object_ref node
78//
79// node must be non-NULL
80inline bool IsObjectNode(wxXmlNode *node)
81{
82 return node->GetType() == wxXML_ELEMENT_NODE &&
83 (node->GetName() == wxS("object") ||
84 node->GetName() == wxS("object_ref"));
85}
86
87} // anonymous namespace
88
78d14f80 89
824e8eaa
VS
90wxXmlResource *wxXmlResource::ms_instance = NULL;
91
92/*static*/ wxXmlResource *wxXmlResource::Get()
93{
94 if ( !ms_instance )
95 ms_instance = new wxXmlResource;
96 return ms_instance;
97}
98
99/*static*/ wxXmlResource *wxXmlResource::Set(wxXmlResource *res)
100{
101 wxXmlResource *old = ms_instance;
102 ms_instance = res;
103 return old;
104}
105
d4a724d4 106wxXmlResource::wxXmlResource(int flags, const wxString& domain)
78d14f80 107{
daa85ee3 108 m_flags = flags;
78d14f80 109 m_version = -1;
eb2d0d23 110 m_data = new wxXmlResourceDataRecords;
d7a80cf5 111 SetDomain(domain);
78d14f80
VS
112}
113
d4a724d4 114wxXmlResource::wxXmlResource(const wxString& filemask, int flags, const wxString& domain)
78d14f80 115{
daa85ee3 116 m_flags = flags;
78d14f80 117 m_version = -1;
eb2d0d23 118 m_data = new wxXmlResourceDataRecords;
d7a80cf5 119 SetDomain(domain);
78d14f80
VS
120 Load(filemask);
121}
122
123wxXmlResource::~wxXmlResource()
124{
125 ClearHandlers();
eb2d0d23 126
f396e5a7
VS
127 for ( wxXmlResourceDataRecords::iterator i = m_data->begin();
128 i != m_data->end(); ++i )
129 {
130 delete *i;
131 }
eb2d0d23 132 delete m_data;
78d14f80
VS
133}
134
d7a80cf5 135void wxXmlResource::SetDomain(const wxString& domain)
d4a724d4 136{
d7a80cf5 137 m_domain = domain;
d4a724d4
RD
138}
139
78d14f80 140
60fd818a
VZ
141/* static */
142wxString wxXmlResource::ConvertFileNameToURL(const wxString& filename)
143{
144 wxString fnd(filename);
145
146 // NB: as Load() and Unload() accept both filenames and URLs (should
147 // probably be changed to filenames only, but embedded resources
148 // currently rely on its ability to handle URLs - FIXME) we need to
149 // determine whether found name is filename and not URL and this is the
150 // fastest/simplest way to do it
151 if (wxFileName::FileExists(fnd))
152 {
153 // Make the name absolute filename, because the app may
154 // change working directory later:
155 wxFileName fn(fnd);
156 if (fn.IsRelative())
157 {
158 fn.MakeAbsolute();
159 fnd = fn.GetFullPath();
160 }
161#if wxUSE_FILESYSTEM
162 fnd = wxFileSystem::FileNameToURL(fnd);
163#endif
164 }
165
166 return fnd;
167}
168
169#if wxUSE_FILESYSTEM
170
171/* static */
172bool wxXmlResource::IsArchive(const wxString& filename)
173{
174 const wxString fnd = filename.Lower();
175
176 return fnd.Matches(wxT("*.zip")) || fnd.Matches(wxT("*.xrs"));
177}
178
179#endif // wxUSE_FILESYSTEM
180
04ae32cd
VS
181bool wxXmlResource::LoadFile(const wxFileName& file)
182{
159852ae 183#if wxUSE_FILESYSTEM
04ae32cd 184 return Load(wxFileSystem::FileNameToURL(file));
159852ae
VS
185#else
186 return Load(file.GetFullPath());
187#endif
04ae32cd
VS
188}
189
2bb9a404
VS
190bool wxXmlResource::LoadAllFiles(const wxString& dirname)
191{
192 bool ok = true;
193 wxArrayString files;
194
195 wxDir::GetAllFiles(dirname, &files, "*.xrc");
196
197 for ( wxArrayString::const_iterator i = files.begin(); i != files.end(); ++i )
198 {
199 if ( !LoadFile(*i) )
200 ok = false;
201 }
202
203 return ok;
204}
205
acd32ffc 206bool wxXmlResource::Load(const wxString& filemask_)
78d14f80 207{
acd32ffc
VS
208 wxString filemask = ConvertFileNameToURL(filemask_);
209
78d14f80
VS
210#if wxUSE_FILESYSTEM
211 wxFileSystem fsys;
212# define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE)
213# define wxXmlFindNext fsys.FindNext()
214#else
215# define wxXmlFindFirst wxFindFirstFile(filemask, wxFILE)
216# define wxXmlFindNext wxFindNextFile()
217#endif
e5bb501b
VZ
218 wxString fnd = wxXmlFindFirst;
219 if ( fnd.empty() )
220 {
221 wxLogError(_("Cannot load resources from '%s'."), filemask);
222 return false;
223 }
224
ec157c8f 225 while (!fnd.empty())
78d14f80
VS
226 {
227#if wxUSE_FILESYSTEM
60fd818a 228 if ( IsArchive(fnd) )
78d14f80 229 {
e5bb501b
VZ
230 if ( !Load(fnd + wxT("#zip:*.xrc")) )
231 return false;
78d14f80 232 }
60fd818a
VZ
233 else // a single resource URL
234#endif // wxUSE_FILESYSTEM
78d14f80 235 {
f396e5a7
VS
236 wxXmlResourceDataRecord *drec = new wxXmlResourceDataRecord;
237 drec->File = fnd;
eb2d0d23 238 Data().push_back(drec);
78d14f80
VS
239 }
240
e5bb501b 241 fnd = wxXmlFindNext;
78d14f80
VS
242 }
243# undef wxXmlFindFirst
244# undef wxXmlFindNext
e5bb501b
VZ
245
246 return UpdateResources();
78d14f80
VS
247}
248
60fd818a
VZ
249bool wxXmlResource::Unload(const wxString& filename)
250{
251 wxASSERT_MSG( !wxIsWild(filename),
252 _T("wildcards not supported by wxXmlResource::Unload()") );
253
254 wxString fnd = ConvertFileNameToURL(filename);
255#if wxUSE_FILESYSTEM
256 const bool isArchive = IsArchive(fnd);
257 if ( isArchive )
258 fnd += _T("#zip:");
259#endif // wxUSE_FILESYSTEM
260
261 bool unloaded = false;
eb2d0d23
VS
262 for ( wxXmlResourceDataRecords::iterator i = Data().begin();
263 i != Data().end(); ++i )
60fd818a
VZ
264 {
265#if wxUSE_FILESYSTEM
266 if ( isArchive )
267 {
f396e5a7 268 if ( (*i)->File.StartsWith(fnd) )
60fd818a
VZ
269 unloaded = true;
270 // don't break from the loop, we can have other matching files
271 }
272 else // a single resource URL
273#endif // wxUSE_FILESYSTEM
274 {
f396e5a7 275 if ( (*i)->File == fnd )
60fd818a 276 {
f8b1df0b 277 delete *i;
eb2d0d23 278 Data().erase(i);
60fd818a
VZ
279 unloaded = true;
280
281 // no sense in continuing, there is only one file with this URL
282 break;
283 }
284 }
285 }
286
287 return unloaded;
288}
289
78d14f80 290
854e189f 291IMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject)
78d14f80
VS
292
293void wxXmlResource::AddHandler(wxXmlResourceHandler *handler)
294{
eb2d0d23 295 m_handlers.push_back(handler);
78d14f80
VS
296 handler->SetParentResource(this);
297}
298
92e898b0
RD
299void wxXmlResource::InsertHandler(wxXmlResourceHandler *handler)
300{
eb2d0d23 301 m_handlers.insert(m_handlers.begin(), handler);
92e898b0
RD
302 handler->SetParentResource(this);
303}
304
78d14f80
VS
305
306
307void wxXmlResource::ClearHandlers()
308{
eb2d0d23
VS
309 for ( wxVector<wxXmlResourceHandler*>::iterator i = m_handlers.begin();
310 i != m_handlers.end(); ++i )
311 delete *i;
312 m_handlers.clear();
78d14f80
VS
313}
314
315
78d14f80
VS
316wxMenu *wxXmlResource::LoadMenu(const wxString& name)
317{
318 return (wxMenu*)CreateResFromNode(FindResource(name, wxT("wxMenu")), NULL, NULL);
319}
320
321
322
4a1b9596 323wxMenuBar *wxXmlResource::LoadMenuBar(wxWindow *parent, const wxString& name)
78d14f80 324{
4a1b9596 325 return (wxMenuBar*)CreateResFromNode(FindResource(name, wxT("wxMenuBar")), parent, NULL);
78d14f80
VS
326}
327
328
329
4a1b9596 330#if wxUSE_TOOLBAR
78d14f80
VS
331wxToolBar *wxXmlResource::LoadToolBar(wxWindow *parent, const wxString& name)
332{
333 return (wxToolBar*)CreateResFromNode(FindResource(name, wxT("wxToolBar")), parent, NULL);
334}
4a1b9596 335#endif
78d14f80
VS
336
337
338wxDialog *wxXmlResource::LoadDialog(wxWindow *parent, const wxString& name)
339{
4dd75a6a 340 return (wxDialog*)CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, NULL);
78d14f80
VS
341}
342
343bool wxXmlResource::LoadDialog(wxDialog *dlg, wxWindow *parent, const wxString& name)
344{
345 return CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, dlg) != NULL;
346}
347
348
349
350wxPanel *wxXmlResource::LoadPanel(wxWindow *parent, const wxString& name)
351{
352 return (wxPanel*)CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, NULL);
353}
354
355bool wxXmlResource::LoadPanel(wxPanel *panel, wxWindow *parent, const wxString& name)
356{
357 return CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, panel) != NULL;
358}
359
92e898b0
RD
360wxFrame *wxXmlResource::LoadFrame(wxWindow* parent, const wxString& name)
361{
362 return (wxFrame*)CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, NULL);
363}
364
78d14f80
VS
365bool wxXmlResource::LoadFrame(wxFrame* frame, wxWindow *parent, const wxString& name)
366{
367 return CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, frame) != NULL;
368}
369
370wxBitmap wxXmlResource::LoadBitmap(const wxString& name)
371{
372 wxBitmap *bmp = (wxBitmap*)CreateResFromNode(
373 FindResource(name, wxT("wxBitmap")), NULL, NULL);
374 wxBitmap rt;
375
376 if (bmp) { rt = *bmp; delete bmp; }
377 return rt;
378}
379
380wxIcon wxXmlResource::LoadIcon(const wxString& name)
381{
382 wxIcon *icon = (wxIcon*)CreateResFromNode(
383 FindResource(name, wxT("wxIcon")), NULL, NULL);
384 wxIcon rt;
385
386 if (icon) { rt = *icon; delete icon; }
387 return rt;
388}
389
92e898b0
RD
390
391wxObject *wxXmlResource::LoadObject(wxWindow *parent, const wxString& name, const wxString& classname)
392{
393 return CreateResFromNode(FindResource(name, classname), parent, NULL);
394}
395
396bool wxXmlResource::LoadObject(wxObject *instance, wxWindow *parent, const wxString& name, const wxString& classname)
397{
398 return CreateResFromNode(FindResource(name, classname), parent, instance) != NULL;
399}
400
401
78d14f80
VS
402bool wxXmlResource::AttachUnknownControl(const wxString& name,
403 wxWindow *control, wxWindow *parent)
404{
405 if (parent == NULL)
406 parent = control->GetParent();
407 wxWindow *container = parent->FindWindow(name + wxT("_container"));
408 if (!container)
409 {
819559b2 410 wxLogError("Cannot find container for unknown control '%s'.", name);
f80ea77b 411 return false;
78d14f80
VS
412 }
413 return control->Reparent(container);
414}
415
416
77b2f9b1 417static void ProcessPlatformProperty(wxXmlNode *node)
78d14f80
VS
418{
419 wxString s;
420 bool isok;
421
422 wxXmlNode *c = node->GetChildren();
423 while (c)
424 {
f80ea77b 425 isok = false;
288b6107 426 if (!c->GetAttribute(wxT("platform"), &s))
f80ea77b 427 isok = true;
78d14f80
VS
428 else
429 {
2b5f62a0 430 wxStringTokenizer tkn(s, wxT(" |"));
78d14f80
VS
431
432 while (tkn.HasMoreTokens())
433 {
434 s = tkn.GetNextToken();
84389518 435#ifdef __WINDOWS__
d003330c
VS
436 if (s == wxT("win")) isok = true;
437#endif
b380439d 438#if defined(__MAC__) || defined(__APPLE__)
d003330c 439 if (s == wxT("mac")) isok = true;
b380439d
RD
440#elif defined(__UNIX__)
441 if (s == wxT("unix")) isok = true;
78d14f80 442#endif
d003330c
VS
443#ifdef __OS2__
444 if (s == wxT("os2")) isok = true;
445#endif
446
447 if (isok)
448 break;
78d14f80
VS
449 }
450 }
451
452 if (isok)
d7b1d73c 453 {
78d14f80 454 ProcessPlatformProperty(c);
d7b1d73c
VS
455 c = c->GetNext();
456 }
78d14f80
VS
457 else
458 {
d7b1d73c 459 wxXmlNode *c2 = c->GetNext();
db59a97c 460 node->RemoveChild(c);
78d14f80 461 delete c;
d7b1d73c 462 c = c2;
78d14f80 463 }
78d14f80
VS
464 }
465}
466
467
468
d614f51b 469bool wxXmlResource::UpdateResources()
78d14f80 470{
d614f51b 471 bool rt = true;
78d14f80
VS
472 bool modif;
473# if wxUSE_FILESYSTEM
474 wxFSFile *file = NULL;
19d0f58d 475 wxUnusedVar(file);
78d14f80
VS
476 wxFileSystem fsys;
477# endif
478
480505bc
VS
479 wxString encoding(wxT("UTF-8"));
480#if !wxUSE_UNICODE && wxUSE_INTL
481 if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 )
482 {
75d38380
VS
483 // In case we are not using wxLocale to translate strings, convert the
484 // strings GUI's charset. This must not be done when wxXRC_USE_LOCALE
485 // is on, because it could break wxGetTranslation lookup.
480505bc
VS
486 encoding = wxLocale::GetSystemEncodingName();
487 }
488#endif
489
eb2d0d23
VS
490 for ( wxXmlResourceDataRecords::iterator i = Data().begin();
491 i != Data().end(); ++i )
78d14f80 492 {
f396e5a7
VS
493 wxXmlResourceDataRecord* const rec = *i;
494
495 modif = (rec->Doc == NULL);
78d14f80 496
648db587 497 if (!modif && !(m_flags & wxXRC_NO_RELOADING))
78d14f80
VS
498 {
499# if wxUSE_FILESYSTEM
f396e5a7 500 file = fsys.OpenFile(rec->File);
34af0de4 501# if wxUSE_DATETIME
f396e5a7 502 modif = file && file->GetModificationTime() > rec->Time;
34af0de4
VZ
503# else // wxUSE_DATETIME
504 modif = true;
505# endif // wxUSE_DATETIME
78d14f80 506 if (!file)
d614f51b 507 {
f396e5a7 508 wxLogError(_("Cannot open file '%s'."), rec->File);
d614f51b
VS
509 rt = false;
510 }
78d14f80 511 wxDELETE(file);
19d0f58d 512 wxUnusedVar(file);
34af0de4
VZ
513# else // wxUSE_FILESYSTEM
514# if wxUSE_DATETIME
f396e5a7 515 modif = wxDateTime(wxFileModificationTime(rec->File)) > rec->Time;
34af0de4
VZ
516# else // wxUSE_DATETIME
517 modif = true;
518# endif // wxUSE_DATETIME
519# endif // wxUSE_FILESYSTEM
78d14f80
VS
520 }
521
522 if (modif)
523 {
f396e5a7 524 wxLogTrace(_T("xrc"), _T("opening file '%s'"), rec->File);
648db587 525
480505bc 526 wxInputStream *stream = NULL;
78d14f80
VS
527
528# if wxUSE_FILESYSTEM
f396e5a7 529 file = fsys.OpenFile(rec->File);
f80ea77b
WS
530 if (file)
531 stream = file->GetStream();
78d14f80 532# else
f396e5a7 533 stream = new wxFileInputStream(rec->File);
78d14f80
VS
534# endif
535
536 if (stream)
537 {
f396e5a7
VS
538 delete rec->Doc;
539 rec->Doc = new wxXmlDocument;
78d14f80 540 }
9690b006 541 if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding))
78d14f80 542 {
480505bc 543 wxLogError(_("Cannot load resources from file '%s'."),
f396e5a7
VS
544 rec->File);
545 wxDELETE(rec->Doc);
d614f51b 546 rt = false;
78d14f80 547 }
f396e5a7 548 else if (rec->Doc->GetRoot()->GetName() != wxT("resource"))
78d14f80 549 {
819559b2
VS
550 ReportError
551 (
552 rec->Doc->GetRoot(),
553 "invalid XRC resource, doesn't have root node <resource>"
554 );
f396e5a7 555 wxDELETE(rec->Doc);
d614f51b 556 rt = false;
78d14f80
VS
557 }
558 else
f80ea77b 559 {
78d14f80
VS
560 long version;
561 int v1, v2, v3, v4;
f396e5a7 562 wxString verstr = rec->Doc->GetRoot()->GetAttribute(
78d14f80
VS
563 wxT("version"), wxT("0.0.0.0"));
564 if (wxSscanf(verstr.c_str(), wxT("%i.%i.%i.%i"),
565 &v1, &v2, &v3, &v4) == 4)
566 version = v1*256*256*256+v2*256*256+v3*256+v4;
567 else
568 version = 0;
569 if (m_version == -1)
570 m_version = version;
571 if (m_version != version)
d614f51b 572 {
819559b2 573 wxLogError("Resource files must have same version number.");
d614f51b
VS
574 rt = false;
575 }
78d14f80 576
f396e5a7 577 ProcessPlatformProperty(rec->Doc->GetRoot());
34af0de4 578#if wxUSE_DATETIME
496f0a58 579#if wxUSE_FILESYSTEM
f396e5a7 580 rec->Time = file->GetModificationTime();
34af0de4 581#else // wxUSE_FILESYSTEM
f396e5a7 582 rec->Time = wxDateTime(wxFileModificationTime(rec->File));
34af0de4
VZ
583#endif // wxUSE_FILESYSTEM
584#endif // wxUSE_DATETIME
f80ea77b 585 }
78d14f80
VS
586
587# if wxUSE_FILESYSTEM
f80ea77b
WS
588 wxDELETE(file);
589 wxUnusedVar(file);
78d14f80 590# else
f80ea77b 591 wxDELETE(stream);
78d14f80
VS
592# endif
593 }
594 }
d614f51b
VS
595
596 return rt;
78d14f80
VS
597}
598
b272b6dc
RD
599wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,
600 const wxString& name,
601 const wxString& classname,
23239d94 602 bool recursive) const
47793ab8 603{
47793ab8
VS
604 wxXmlNode *node;
605
606 // first search for match at the top-level nodes (as this is
607 // where the resource is most commonly looked for):
608 for (node = parent->GetChildren(); node; node = node->GetNext())
609 {
23239d94 610 if ( IsObjectNode(node) && node->GetAttribute(wxS("name")) == name )
2b5f62a0 611 {
23239d94
VZ
612 // empty class name matches everything
613 if ( classname.empty() )
2b5f62a0 614 return node;
23239d94
VZ
615
616 wxString cls(node->GetAttribute(wxS("class")));
617
288b6107 618 // object_ref may not have 'class' attribute:
23239d94 619 if (cls.empty() && node->GetName() == wxS("object_ref"))
2b5f62a0 620 {
23239d94 621 wxString refName = node->GetAttribute(wxS("ref"));
2b5f62a0
VZ
622 if (refName.empty())
623 continue;
23239d94
VZ
624
625 const wxXmlNode * const refNode = GetResourceNode(refName);
626 if ( refNode )
627 cls = refNode->GetAttribute(wxS("class"));
2b5f62a0 628 }
23239d94
VZ
629
630 if ( cls == classname )
631 return node;
2b5f62a0 632 }
47793ab8
VS
633 }
634
23239d94 635 // then recurse in child nodes
47793ab8 636 if ( recursive )
23239d94 637 {
47793ab8
VS
638 for (node = parent->GetChildren(); node; node = node->GetNext())
639 {
23239d94 640 if ( IsObjectNode(node) )
47793ab8 641 {
f80ea77b 642 wxXmlNode* found = DoFindResource(node, name, classname, true);
47793ab8
VS
643 if ( found )
644 return found;
645 }
646 }
23239d94 647 }
47793ab8 648
23239d94 649 return NULL;
47793ab8 650}
78d14f80 651
b272b6dc 652wxXmlNode *wxXmlResource::FindResource(const wxString& name,
47793ab8
VS
653 const wxString& classname,
654 bool recursive)
78d14f80 655{
23239d94
VZ
656 wxString path;
657 wxXmlNode * const
658 node = GetResourceNodeAndLocation(name, classname, recursive, &path);
659
660 if ( !node )
661 {
819559b2
VS
662 ReportError
663 (
664 NULL,
665 wxString::Format
666 (
667 "XRC resource \"%s\" (class \"%s\") not found",
668 name, classname
669 )
670 );
23239d94
VZ
671 }
672#if wxUSE_FILESYSTEM
673 else // node was found
674 {
675 // ensure that relative paths work correctly when loading this node
676 // (which should happen as soon as we return as FindResource() result
677 // is always passed to CreateResFromNode())
678 m_curFileSystem.ChangePathTo(path);
679 }
680#endif // wxUSE_FILESYSTEM
681
682 return node;
683}
684
685wxXmlNode *
686wxXmlResource::GetResourceNodeAndLocation(const wxString& name,
687 const wxString& classname,
688 bool recursive,
689 wxString *path) const
690{
691 // ensure everything is up-to-date: this is needed to support on-remand
692 // reloading of XRC files
693 const_cast<wxXmlResource *>(this)->UpdateResources();
78d14f80 694
eb2d0d23
VS
695 for ( wxXmlResourceDataRecords::const_iterator f = Data().begin();
696 f != Data().end(); ++f )
78d14f80 697 {
23239d94
VZ
698 wxXmlResourceDataRecord *const rec = *f;
699 wxXmlDocument * const doc = rec->Doc;
700 if ( !doc || !doc->GetRoot() )
47793ab8
VS
701 continue;
702
23239d94
VZ
703 wxXmlNode * const
704 found = DoFindResource(doc->GetRoot(), name, classname, recursive);
47793ab8
VS
705 if ( found )
706 {
23239d94
VZ
707 if ( path )
708 *path = rec->File;
709
47793ab8
VS
710 return found;
711 }
78d14f80
VS
712 }
713
78d14f80
VS
714 return NULL;
715}
716
47793ab8
VS
717static void MergeNodes(wxXmlNode& dest, wxXmlNode& with)
718{
288b6107
VS
719 // Merge attributes:
720 for ( wxXmlAttribute *attr = with.GetAttributes();
721 attr; attr = attr->GetNext() )
47793ab8 722 {
288b6107
VS
723 wxXmlAttribute *dattr;
724 for (dattr = dest.GetAttributes(); dattr; dattr = dattr->GetNext())
47793ab8 725 {
b272b6dc 726
288b6107 727 if ( dattr->GetName() == attr->GetName() )
47793ab8 728 {
288b6107 729 dattr->SetValue(attr->GetValue());
47793ab8
VS
730 break;
731 }
732 }
78d14f80 733
288b6107
VS
734 if ( !dattr )
735 dest.AddAttribute(attr->GetName(), attr->GetValue());
47793ab8
VS
736 }
737
738 // Merge child nodes:
739 for (wxXmlNode* node = with.GetChildren(); node; node = node->GetNext())
740 {
288b6107 741 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
47793ab8
VS
742 wxXmlNode *dnode;
743
744 for (dnode = dest.GetChildren(); dnode; dnode = dnode->GetNext() )
745 {
746 if ( dnode->GetName() == node->GetName() &&
288b6107 747 dnode->GetAttribute(wxT("name"), wxEmptyString) == name &&
47793ab8
VS
748 dnode->GetType() == node->GetType() )
749 {
750 MergeNodes(*dnode, *node);
751 break;
752 }
753 }
754
755 if ( !dnode )
b26a650c
VZ
756 {
757 static const wxChar *AT_END = wxT("end");
288b6107 758 wxString insert_pos = node->GetAttribute(wxT("insert_at"), AT_END);
b26a650c
VZ
759 if ( insert_pos == AT_END )
760 {
761 dest.AddChild(new wxXmlNode(*node));
762 }
763 else if ( insert_pos == wxT("begin") )
764 {
765 dest.InsertChild(new wxXmlNode(*node), dest.GetChildren());
766 }
767 }
47793ab8
VS
768 }
769
0bca0373 770 if ( dest.GetType() == wxXML_TEXT_NODE && with.GetContent().length() )
47793ab8
VS
771 dest.SetContent(with.GetContent());
772}
78d14f80 773
317a0d73
VS
774wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
775 wxObject *instance,
776 wxXmlResourceHandler *handlerToUse)
78d14f80
VS
777{
778 if (node == NULL) return NULL;
779
47793ab8
VS
780 // handling of referenced resource
781 if ( node->GetName() == wxT("object_ref") )
782 {
288b6107 783 wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString);
f80ea77b 784 wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
47793ab8
VS
785
786 if ( !refNode )
787 {
819559b2
VS
788 ReportError
789 (
790 node,
791 wxString::Format
792 (
793 "referenced object node with ref=\"%s\" not found",
794 refName
795 )
796 );
47793ab8
VS
797 return NULL;
798 }
799
800 wxXmlNode copy(*refNode);
801 MergeNodes(copy, *node);
802
803 return CreateResFromNode(&copy, parent, instance);
804 }
805
317a0d73 806 if (handlerToUse)
b380439d 807 {
317a0d73 808 if (handlerToUse->CanHandle(node))
8e8a4e85 809 {
317a0d73 810 return handlerToUse->CreateResource(node, parent, instance);
8e8a4e85 811 }
317a0d73
VS
812 }
813 else if (node->GetName() == wxT("object"))
b380439d 814 {
eb2d0d23
VS
815 for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
816 h != m_handlers.end(); ++h )
317a0d73 817 {
eb2d0d23 818 wxXmlResourceHandler *handler = *h;
317a0d73 819 if (handler->CanHandle(node))
317a0d73 820 return handler->CreateResource(node, parent, instance);
78d14f80 821 }
78d14f80
VS
822 }
823
819559b2
VS
824 ReportError
825 (
826 node,
827 wxString::Format
828 (
829 "no handler found for XML node \"%s\" (class \"%s\")",
830 node->GetName(),
831 node->GetAttribute("class", wxEmptyString)
832 )
833 );
78d14f80
VS
834 return NULL;
835}
836
837
eb2d0d23
VS
838class wxXmlSubclassFactories : public wxVector<wxXmlSubclassFactory*>
839{
840 // this is a class so that it can be forward-declared
841};
2b5f62a0 842
eb2d0d23 843wxXmlSubclassFactories *wxXmlResource::ms_subclassFactories = NULL;
2b5f62a0
VZ
844
845/*static*/ void wxXmlResource::AddSubclassFactory(wxXmlSubclassFactory *factory)
846{
847 if (!ms_subclassFactories)
848 {
eb2d0d23 849 ms_subclassFactories = new wxXmlSubclassFactories;
2b5f62a0 850 }
eb2d0d23 851 ms_subclassFactories->push_back(factory);
2b5f62a0
VZ
852}
853
854class wxXmlSubclassFactoryCXX : public wxXmlSubclassFactory
855{
856public:
857 ~wxXmlSubclassFactoryCXX() {}
858
859 wxObject *Create(const wxString& className)
860 {
861 wxClassInfo* classInfo = wxClassInfo::FindClass(className);
862
863 if (classInfo)
864 return classInfo->CreateObject();
865 else
866 return NULL;
867 }
868};
869
870
871
78d14f80 872
78d14f80
VS
873wxXmlResourceHandler::wxXmlResourceHandler()
874 : m_node(NULL), m_parent(NULL), m_instance(NULL),
9a8d8c5a 875 m_parentAsWindow(NULL)
78d14f80
VS
876{}
877
878
879
880wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance)
881{
882 wxXmlNode *myNode = m_node;
883 wxString myClass = m_class;
884 wxObject *myParent = m_parent, *myInstance = m_instance;
9a8d8c5a 885 wxWindow *myParentAW = m_parentAsWindow;
78d14f80 886
daa85ee3 887 m_instance = instance;
288b6107 888 if (!m_instance && node->HasAttribute(wxT("subclass")) &&
daa85ee3
VS
889 !(m_resource->GetFlags() & wxXRC_NO_SUBCLASSING))
890 {
288b6107 891 wxString subclass = node->GetAttribute(wxT("subclass"), wxEmptyString);
2b5f62a0 892 if (!subclass.empty())
daa85ee3 893 {
eb2d0d23
VS
894 for (wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
895 i != wxXmlResource::ms_subclassFactories->end(); ++i)
2b5f62a0 896 {
eb2d0d23 897 m_instance = (*i)->Create(subclass);
2b5f62a0
VZ
898 if (m_instance)
899 break;
900 }
daa85ee3 901
2b5f62a0
VZ
902 if (!m_instance)
903 {
288b6107 904 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
819559b2
VS
905 ReportError
906 (
907 node,
908 wxString::Format
909 (
910 "subclass \"%s\" not found for resource \"%s\", not subclassing",
911 subclass, name
912 )
913 );
2b5f62a0
VZ
914 }
915 }
daa85ee3
VS
916 }
917
78d14f80 918 m_node = node;
288b6107 919 m_class = node->GetAttribute(wxT("class"), wxEmptyString);
78d14f80 920 m_parent = parent;
78d14f80 921 m_parentAsWindow = wxDynamicCast(m_parent, wxWindow);
78d14f80
VS
922
923 wxObject *returned = DoCreateResource();
924
925 m_node = myNode;
926 m_class = myClass;
927 m_parent = myParent; m_parentAsWindow = myParentAW;
9a8d8c5a 928 m_instance = myInstance;
78d14f80
VS
929
930 return returned;
931}
932
933
934void wxXmlResourceHandler::AddStyle(const wxString& name, int value)
935{
936 m_styleNames.Add(name);
937 m_styleValues.Add(value);
938}
939
940
941
942void wxXmlResourceHandler::AddWindowStyles()
943{
9dc579b3 944 XRC_ADD_STYLE(wxCLIP_CHILDREN);
d54a3e73
VZ
945
946 // the border styles all have the old and new names, recognize both for now
947 XRC_ADD_STYLE(wxSIMPLE_BORDER); XRC_ADD_STYLE(wxBORDER_SIMPLE);
948 XRC_ADD_STYLE(wxSUNKEN_BORDER); XRC_ADD_STYLE(wxBORDER_SUNKEN);
949 XRC_ADD_STYLE(wxDOUBLE_BORDER); XRC_ADD_STYLE(wxBORDER_DOUBLE);
950 XRC_ADD_STYLE(wxRAISED_BORDER); XRC_ADD_STYLE(wxBORDER_RAISED);
951 XRC_ADD_STYLE(wxSTATIC_BORDER); XRC_ADD_STYLE(wxBORDER_STATIC);
952 XRC_ADD_STYLE(wxNO_BORDER); XRC_ADD_STYLE(wxBORDER_NONE);
953
daa85ee3
VS
954 XRC_ADD_STYLE(wxTRANSPARENT_WINDOW);
955 XRC_ADD_STYLE(wxWANTS_CHARS);
43840d8b 956 XRC_ADD_STYLE(wxTAB_TRAVERSAL);
daa85ee3 957 XRC_ADD_STYLE(wxNO_FULL_REPAINT_ON_RESIZE);
7539ba56 958 XRC_ADD_STYLE(wxFULL_REPAINT_ON_RESIZE);
162a4f93 959 XRC_ADD_STYLE(wxALWAYS_SHOW_SB);
9f4ed861 960 XRC_ADD_STYLE(wxWS_EX_BLOCK_EVENTS);
b0802e64 961 XRC_ADD_STYLE(wxWS_EX_VALIDATE_RECURSIVELY);
78d14f80
VS
962}
963
964
965
966bool wxXmlResourceHandler::HasParam(const wxString& param)
967{
968 return (GetParamNode(param) != NULL);
969}
970
971
972int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
973{
974 wxString s = GetParamValue(param);
975
976 if (!s) return defaults;
977
2b5f62a0 978 wxStringTokenizer tkn(s, wxT("| \t\n"), wxTOKEN_STRTOK);
78d14f80
VS
979 int style = 0;
980 int index;
981 wxString fl;
982 while (tkn.HasMoreTokens())
983 {
984 fl = tkn.GetNextToken();
985 index = m_styleNames.Index(fl);
986 if (index != wxNOT_FOUND)
819559b2 987 {
78d14f80 988 style |= m_styleValues[index];
819559b2 989 }
78d14f80 990 else
819559b2
VS
991 {
992 ReportParamError
993 (
994 param,
995 wxString::Format("unknown style flag \"%s\"", fl)
996 );
997 }
78d14f80
VS
998 }
999 return style;
1000}
1001
1002
1003
ee1046d1 1004wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate)
78d14f80 1005{
7b56015f
VS
1006 wxXmlNode *parNode = GetParamNode(param);
1007 wxString str1(GetNodeContent(parNode));
78d14f80 1008 wxString str2;
424af7aa
VS
1009
1010 // "\\" wasn't translated to "\" prior to 2.5.3.0:
1011 const bool escapeBackslash = (m_resource->CompareVersion(2,5,3,0) >= 0);
78d14f80 1012
b272b6dc
RD
1013 // VS: First version of XRC resources used $ instead of & (which is
1014 // illegal in XML), but later I realized that '_' fits this purpose
718cf160 1015 // much better (because &File means "File with F underlined").
424af7aa
VS
1016 const wxChar amp_char = (m_resource->CompareVersion(2,3,0,1) < 0)
1017 ? '$' : '_';
78d14f80 1018
424af7aa 1019 for ( wxString::const_iterator dt = str1.begin(); dt != str1.end(); ++dt )
78d14f80
VS
1020 {
1021 // Remap amp_char to &, map double amp_char to amp_char (for things
1022 // like "&File..." -- this is illegal in XML, so we use "_File..."):
424af7aa 1023 if ( *dt == amp_char )
78d14f80
VS
1024 {
1025 if ( *(++dt) == amp_char )
1026 str2 << amp_char;
1027 else
1028 str2 << wxT('&') << *dt;
1029 }
984c33c9 1030 // Remap \n to CR, \r to LF, \t to TAB, \\ to \:
424af7aa
VS
1031 else if ( *dt == wxT('\\') )
1032 {
1033 switch ( (*(++dt)).GetValue() )
78d14f80 1034 {
984c33c9
VS
1035 case wxT('n'):
1036 str2 << wxT('\n');
1037 break;
e7a3a5a5 1038
984c33c9
VS
1039 case wxT('t'):
1040 str2 << wxT('\t');
1041 break;
e7a3a5a5 1042
984c33c9
VS
1043 case wxT('r'):
1044 str2 << wxT('\r');
1045 break;
1046
1047 case wxT('\\') :
1048 // "\\" wasn't translated to "\" prior to 2.5.3.0:
424af7aa 1049 if ( escapeBackslash )
984c33c9
VS
1050 {
1051 str2 << wxT('\\');
1052 break;
1053 }
1054 // else fall-through to default: branch below
e7a3a5a5 1055
984c33c9
VS
1056 default:
1057 str2 << wxT('\\') << *dt;
1058 break;
78d14f80 1059 }
424af7aa
VS
1060 }
1061 else
1062 {
1063 str2 << *dt;
1064 }
78d14f80 1065 }
b272b6dc 1066
7b56015f
VS
1067 if (m_resource->GetFlags() & wxXRC_USE_LOCALE)
1068 {
1069 if (translate && parNode &&
288b6107 1070 parNode->GetAttribute(wxT("translate"), wxEmptyString) != wxT("0"))
7b56015f 1071 {
d4a724d4 1072 return wxGetTranslation(str2, m_resource->GetDomain());
7b56015f
VS
1073 }
1074 else
1075 {
1076#if wxUSE_UNICODE
1077 return str2;
1078#else
1079 // The string is internally stored as UTF-8, we have to convert
1080 // it into system's default encoding so that it can be displayed:
6251e0ea 1081 return wxString(str2.wc_str(wxConvUTF8), wxConvLocal);
7b56015f
VS
1082#endif
1083 }
1084 }
8516a98b
DS
1085
1086 // If wxXRC_USE_LOCALE is not set, then the string is already in
1087 // system's default encoding in ANSI build, so we don't have to
1088 // do anything special here.
1089 return str2;
78d14f80
VS
1090}
1091
1092
1093
1094long wxXmlResourceHandler::GetLong(const wxString& param, long defaultv)
1095{
1096 long value;
1097 wxString str1 = GetParamValue(param);
1098
1099 if (!str1.ToLong(&value))
1100 value = defaultv;
1101
1102 return value;
1103}
e7a3a5a5 1104
1df61962
VS
1105float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv)
1106{
1d9473d3 1107 wxString str = GetParamValue(param);
1df61962 1108
cfd91598 1109#if wxUSE_INTL
1d9473d3
VZ
1110 // strings in XRC always use C locale but wxString::ToDouble() uses the
1111 // current one, so transform the string to it supposing that the only
1112 // difference between them is the decimal separator
1113 //
1114 // TODO: use wxString::ToCDouble() when we have it
1115 str.Replace(wxT("."), wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
1116 wxLOCALE_CAT_NUMBER));
cfd91598 1117#endif // wxUSE_INTL
e7a3a5a5 1118
1d9473d3
VZ
1119 double value;
1120 if (!str.ToDouble(&value))
1df61962
VS
1121 value = defaultv;
1122
17a1ebd1 1123 return wx_truncate_cast(float, value);
1df61962 1124}
78d14f80 1125
af1337b0 1126
78d14f80
VS
1127int wxXmlResourceHandler::GetID()
1128{
13de23f6 1129 return wxXmlResource::GetXRCID(GetName());
78d14f80
VS
1130}
1131
1132
af1337b0 1133
78d14f80
VS
1134wxString wxXmlResourceHandler::GetName()
1135{
288b6107 1136 return m_node->GetAttribute(wxT("name"), wxT("-1"));
78d14f80
VS
1137}
1138
1139
1140
8758875e
VZ
1141bool wxXmlResourceHandler::GetBoolAttr(const wxString& attr, bool defaultv)
1142{
1143 wxString v;
1144 return m_node->GetAttribute(attr, &v) ? v == '1' : defaultv;
1145}
1146
78d14f80
VS
1147bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv)
1148{
8758875e 1149 const wxString v = GetParamValue(param);
8516a98b 1150
8758875e 1151 return v.empty() ? defaultv : (v == '1');
78d14f80
VS
1152}
1153
1154
1df61962
VS
1155static wxColour GetSystemColour(const wxString& name)
1156{
1157 if (!name.empty())
1158 {
1159 #define SYSCLR(clr) \
1160 if (name == _T(#clr)) return wxSystemSettings::GetColour(clr);
1161 SYSCLR(wxSYS_COLOUR_SCROLLBAR)
1162 SYSCLR(wxSYS_COLOUR_BACKGROUND)
1163 SYSCLR(wxSYS_COLOUR_DESKTOP)
1164 SYSCLR(wxSYS_COLOUR_ACTIVECAPTION)
1165 SYSCLR(wxSYS_COLOUR_INACTIVECAPTION)
1166 SYSCLR(wxSYS_COLOUR_MENU)
1167 SYSCLR(wxSYS_COLOUR_WINDOW)
1168 SYSCLR(wxSYS_COLOUR_WINDOWFRAME)
1169 SYSCLR(wxSYS_COLOUR_MENUTEXT)
1170 SYSCLR(wxSYS_COLOUR_WINDOWTEXT)
1171 SYSCLR(wxSYS_COLOUR_CAPTIONTEXT)
1172 SYSCLR(wxSYS_COLOUR_ACTIVEBORDER)
1173 SYSCLR(wxSYS_COLOUR_INACTIVEBORDER)
1174 SYSCLR(wxSYS_COLOUR_APPWORKSPACE)
1175 SYSCLR(wxSYS_COLOUR_HIGHLIGHT)
1176 SYSCLR(wxSYS_COLOUR_HIGHLIGHTTEXT)
1177 SYSCLR(wxSYS_COLOUR_BTNFACE)
1178 SYSCLR(wxSYS_COLOUR_3DFACE)
1179 SYSCLR(wxSYS_COLOUR_BTNSHADOW)
1180 SYSCLR(wxSYS_COLOUR_3DSHADOW)
1181 SYSCLR(wxSYS_COLOUR_GRAYTEXT)
1182 SYSCLR(wxSYS_COLOUR_BTNTEXT)
1183 SYSCLR(wxSYS_COLOUR_INACTIVECAPTIONTEXT)
1184 SYSCLR(wxSYS_COLOUR_BTNHIGHLIGHT)
1185 SYSCLR(wxSYS_COLOUR_BTNHILIGHT)
1186 SYSCLR(wxSYS_COLOUR_3DHIGHLIGHT)
1187 SYSCLR(wxSYS_COLOUR_3DHILIGHT)
1188 SYSCLR(wxSYS_COLOUR_3DDKSHADOW)
1189 SYSCLR(wxSYS_COLOUR_3DLIGHT)
1190 SYSCLR(wxSYS_COLOUR_INFOTEXT)
1191 SYSCLR(wxSYS_COLOUR_INFOBK)
1192 SYSCLR(wxSYS_COLOUR_LISTBOX)
1193 SYSCLR(wxSYS_COLOUR_HOTLIGHT)
1194 SYSCLR(wxSYS_COLOUR_GRADIENTACTIVECAPTION)
1195 SYSCLR(wxSYS_COLOUR_GRADIENTINACTIVECAPTION)
1196 SYSCLR(wxSYS_COLOUR_MENUHILIGHT)
1197 SYSCLR(wxSYS_COLOUR_MENUBAR)
1198 #undef SYSCLR
1199 }
1200
1201 return wxNullColour;
1202}
78d14f80 1203
984f1d84 1204wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& defaultv)
78d14f80
VS
1205{
1206 wxString v = GetParamValue(param);
984f1d84
VS
1207
1208 if ( v.empty() )
1209 return defaultv;
1210
68b4e4cf 1211 wxColour clr;
1df61962 1212
68b4e4cf
WS
1213 // wxString -> wxColour conversion
1214 if (!clr.Set(v))
78d14f80 1215 {
1df61962
VS
1216 // the colour doesn't use #RRGGBB format, check if it is symbolic
1217 // colour name:
68b4e4cf 1218 clr = GetSystemColour(v);
1df61962
VS
1219 if (clr.Ok())
1220 return clr;
e7a3a5a5 1221
819559b2
VS
1222 ReportParamError
1223 (
1224 param,
1225 wxString::Format("incorrect colour specification \"%s\"", v)
1226 );
78d14f80
VS
1227 return wxNullColour;
1228 }
1229
68b4e4cf 1230 return clr;
78d14f80
VS
1231}
1232
1c60f644
VS
1233namespace
1234{
1235
1236// if 'param' has stock_id/stock_client, extracts them and returns true
1237bool GetStockArtAttrs(const wxXmlNode *paramNode,
1238 const wxString& defaultArtClient,
1239 wxString& art_id, wxString& art_client)
1240{
1241 if ( paramNode )
1242 {
1243 art_id = paramNode->GetAttribute("stock_id", "");
1244
1245 if ( !art_id.empty() )
1246 {
1247 art_id = wxART_MAKE_ART_ID_FROM_STR(art_id);
1248
1249 art_client = paramNode->GetAttribute("stock_client", "");
1250 if ( art_client.empty() )
1251 art_client = defaultArtClient;
1252 else
1253 art_client = wxART_MAKE_CLIENT_ID_FROM_STR(art_client);
78d14f80 1254
1c60f644
VS
1255 return true;
1256 }
1257 }
1258
1259 return false;
1260}
1261
1262} // anonymous namespace
78d14f80 1263
92e898b0 1264wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
db59a97c
VS
1265 const wxArtClient& defaultArtClient,
1266 wxSize size)
78d14f80 1267{
db59a97c 1268 /* If the bitmap is specified as stock item, query wxArtProvider for it: */
1c60f644
VS
1269 wxString art_id, art_client;
1270 if ( GetStockArtAttrs(GetParamNode(param), defaultArtClient,
1271 art_id, art_client) )
af1337b0 1272 {
1c60f644
VS
1273 wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size));
1274 if ( stockArt.Ok() )
1275 return stockArt;
af1337b0
JS
1276 }
1277
92e898b0 1278 /* ...or load the bitmap from file: */
78d14f80 1279 wxString name = GetParamValue(param);
e7a3a5a5 1280 if (name.empty()) return wxNullBitmap;
78d14f80 1281#if wxUSE_FILESYSTEM
4532786e 1282 wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
78d14f80
VS
1283 if (fsfile == NULL)
1284 {
819559b2
VS
1285 ReportParamError
1286 (
1287 param,
1288 wxString::Format("cannot open bitmap resource \"%s\"", name)
1289 );
78d14f80
VS
1290 return wxNullBitmap;
1291 }
1292 wxImage img(*(fsfile->GetStream()));
1293 delete fsfile;
1294#else
45f3249b 1295 wxImage img(name);
78d14f80 1296#endif
af1337b0 1297
78d14f80
VS
1298 if (!img.Ok())
1299 {
819559b2
VS
1300 ReportParamError
1301 (
1302 param,
1303 wxString::Format("cannot create bitmap from \"%s\"", name)
1304 );
78d14f80
VS
1305 return wxNullBitmap;
1306 }
1307 if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
b272b6dc 1308 return wxBitmap(img);
78d14f80
VS
1309}
1310
78d14f80 1311
92e898b0 1312wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
db59a97c
VS
1313 const wxArtClient& defaultArtClient,
1314 wxSize size)
78d14f80 1315{
78d14f80 1316 wxIcon icon;
db59a97c 1317 icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size));
78d14f80
VS
1318 return icon;
1319}
1320
1c60f644
VS
1321wxIconBundle wxXmlResourceHandler::GetIconBundle(const wxString& param,
1322 const wxArtClient& defaultArtClient)
1323{
1324 wxString art_id, art_client;
1325 if ( GetStockArtAttrs(GetParamNode(param), defaultArtClient,
1326 art_id, art_client) )
1327 {
1328 wxIconBundle stockArt(wxArtProvider::GetIconBundle(art_id, art_client));
1329 if ( stockArt.IsOk() )
1330 return stockArt;
1331 }
1332
1333 const wxString name = GetParamValue(param);
1334 if ( name.empty() )
1335 return wxNullIconBundle;
1336
1337#if wxUSE_FILESYSTEM
1338 wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
1339 if ( fsfile == NULL )
1340 {
1341 ReportParamError
1342 (
1343 param,
1344 wxString::Format("cannot open icon resource \"%s\"", name)
1345 );
1346 return wxNullIconBundle;
1347 }
1348
1349 wxIconBundle bundle(*(fsfile->GetStream()));
1350 delete fsfile;
1351#else
1352 wxIconBundle bundle(name);
1353#endif
1354
1355 if ( !bundle.IsOk() )
1356 {
1357 ReportParamError
1358 (
1359 param,
1360 wxString::Format("cannot create icon from \"%s\"", name)
1361 );
1362 return wxNullIconBundle;
1363 }
1364
1365 return bundle;
1366}
78d14f80
VS
1367
1368
1369wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
1370{
2b5f62a0
VZ
1371 wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!"));
1372
78d14f80
VS
1373 wxXmlNode *n = m_node->GetChildren();
1374
1375 while (n)
1376 {
1377 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
cffff062
VZ
1378 {
1379 // TODO: check that there are no other properties/parameters with
1380 // the same name and log an error if there are (can't do this
1381 // right now as I'm not sure if it's not going to break code
1382 // using this function in unintentional way (i.e. for
1383 // accessing other things than properties), for example
1384 // wxBitmapComboBoxXmlHandler almost surely does
78d14f80 1385 return n;
cffff062 1386 }
78d14f80
VS
1387 n = n->GetNext();
1388 }
1389 return NULL;
1390}
1391
2d672c46
MW
1392bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
1393{
288b6107 1394 return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
2d672c46
MW
1395}
1396
1397
1398
78d14f80
VS
1399wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
1400{
1401 wxXmlNode *n = node;
1402 if (n == NULL) return wxEmptyString;
1403 n = n->GetChildren();
1404
1405 while (n)
1406 {
1407 if (n->GetType() == wxXML_TEXT_NODE ||
1408 n->GetType() == wxXML_CDATA_SECTION_NODE)
1409 return n->GetContent();
1410 n = n->GetNext();
1411 }
1412 return wxEmptyString;
1413}
1414
1415
1416
1417wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
1418{
e7a3a5a5 1419 if (param.empty())
78d14f80
VS
1420 return GetNodeContent(m_node);
1421 else
1422 return GetNodeContent(GetParamNode(param));
1423}
1424
1425
1426
0c00c86f
VS
1427wxSize wxXmlResourceHandler::GetSize(const wxString& param,
1428 wxWindow *windowToUse)
78d14f80
VS
1429{
1430 wxString s = GetParamValue(param);
e7a3a5a5 1431 if (s.empty()) s = wxT("-1,-1");
78d14f80 1432 bool is_dlg;
d1f47235 1433 long sx, sy = 0;
78d14f80 1434
88a7a4e1 1435 is_dlg = s[s.length()-1] == wxT('d');
78d14f80
VS
1436 if (is_dlg) s.RemoveLast();
1437
1438 if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
1439 !s.AfterLast(wxT(',')).ToLong(&sy))
1440 {
819559b2
VS
1441 ReportParamError
1442 (
1443 param,
1444 wxString::Format("cannot parse coordinates value \"%s\"", s)
1445 );
78d14f80
VS
1446 return wxDefaultSize;
1447 }
1448
1449 if (is_dlg)
1450 {
0c00c86f
VS
1451 if (windowToUse)
1452 {
1453 return wxDLG_UNIT(windowToUse, wxSize(sx, sy));
1454 }
1455 else if (m_parentAsWindow)
1456 {
78d14f80 1457 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, sy));
0c00c86f 1458 }
78d14f80
VS
1459 else
1460 {
819559b2
VS
1461 ReportParamError
1462 (
1463 param,
1464 "cannot convert dialog units: dialog unknown"
1465 );
78d14f80
VS
1466 return wxDefaultSize;
1467 }
1468 }
8516a98b
DS
1469
1470 return wxSize(sx, sy);
78d14f80
VS
1471}
1472
1473
1474
1475wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
1476{
1477 wxSize sz = GetSize(param);
1478 return wxPoint(sz.x, sz.y);
1479}
1480
1481
1482
0c00c86f
VS
1483wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
1484 wxCoord defaultv,
1485 wxWindow *windowToUse)
78d14f80
VS
1486{
1487 wxString s = GetParamValue(param);
e7a3a5a5 1488 if (s.empty()) return defaultv;
78d14f80
VS
1489 bool is_dlg;
1490 long sx;
1491
88a7a4e1 1492 is_dlg = s[s.length()-1] == wxT('d');
78d14f80
VS
1493 if (is_dlg) s.RemoveLast();
1494
1495 if (!s.ToLong(&sx))
1496 {
819559b2
VS
1497 ReportParamError
1498 (
1499 param,
1500 wxString::Format("cannot parse dimension value \"%s\"", s)
1501 );
78d14f80
VS
1502 return defaultv;
1503 }
1504
1505 if (is_dlg)
1506 {
0c00c86f
VS
1507 if (windowToUse)
1508 {
1509 return wxDLG_UNIT(windowToUse, wxSize(sx, 0)).x;
1510 }
1511 else if (m_parentAsWindow)
1512 {
78d14f80 1513 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, 0)).x;
0c00c86f 1514 }
78d14f80
VS
1515 else
1516 {
819559b2
VS
1517 ReportParamError
1518 (
1519 param,
1520 "cannot convert dialog units: dialog unknown"
1521 );
78d14f80
VS
1522 return defaultv;
1523 }
1524 }
8516a98b
DS
1525
1526 return sx;
78d14f80
VS
1527}
1528
1529
1df61962
VS
1530// Get system font index using indexname
1531static wxFont GetSystemFont(const wxString& name)
1532{
1533 if (!name.empty())
1534 {
1535 #define SYSFNT(fnt) \
1536 if (name == _T(#fnt)) return wxSystemSettings::GetFont(fnt);
1537 SYSFNT(wxSYS_OEM_FIXED_FONT)
1538 SYSFNT(wxSYS_ANSI_FIXED_FONT)
1539 SYSFNT(wxSYS_ANSI_VAR_FONT)
1540 SYSFNT(wxSYS_SYSTEM_FONT)
1541 SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
1df61962
VS
1542 SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
1543 SYSFNT(wxSYS_DEFAULT_GUI_FONT)
1544 #undef SYSFNT
1545 }
1546
1547 return wxNullFont;
1548}
78d14f80
VS
1549
1550wxFont wxXmlResourceHandler::GetFont(const wxString& param)
1551{
1552 wxXmlNode *font_node = GetParamNode(param);
1553 if (font_node == NULL)
1554 {
819559b2
VS
1555 ReportError(
1556 wxString::Format("cannot find font node \"%s\"", param));
78d14f80
VS
1557 return wxNullFont;
1558 }
1559
1560 wxXmlNode *oldnode = m_node;
1561 m_node = font_node;
1562
1df61962 1563 // font attributes:
78d14f80 1564
1df61962 1565 // size
94245f6d 1566 int isize = -1;
1df61962 1567 bool hasSize = HasParam(wxT("size"));
e7a3a5a5 1568 if (hasSize)
94245f6d 1569 isize = GetLong(wxT("size"), -1);
78d14f80 1570
1df61962
VS
1571 // style
1572 int istyle = wxNORMAL;
1573 bool hasStyle = HasParam(wxT("style"));
1574 if (hasStyle)
1575 {
1576 wxString style = GetParamValue(wxT("style"));
e7a3a5a5 1577 if (style == wxT("italic"))
1df61962 1578 istyle = wxITALIC;
e7a3a5a5 1579 else if (style == wxT("slant"))
1df61962
VS
1580 istyle = wxSLANT;
1581 }
78d14f80 1582
1df61962
VS
1583 // weight
1584 int iweight = wxNORMAL;
1585 bool hasWeight = HasParam(wxT("weight"));
1586 if (hasWeight)
1587 {
1588 wxString weight = GetParamValue(wxT("weight"));
e7a3a5a5 1589 if (weight == wxT("bold"))
1df61962 1590 iweight = wxBOLD;
e7a3a5a5 1591 else if (weight == wxT("light"))
1df61962
VS
1592 iweight = wxLIGHT;
1593 }
e7a3a5a5 1594
1df61962
VS
1595 // underline
1596 bool hasUnderlined = HasParam(wxT("underlined"));
1597 bool underlined = hasUnderlined ? GetBool(wxT("underlined"), false) : false;
78d14f80 1598
1df61962
VS
1599 // family and facename
1600 int ifamily = wxDEFAULT;
1601 bool hasFamily = HasParam(wxT("family"));
1602 if (hasFamily)
78d14f80 1603 {
1df61962
VS
1604 wxString family = GetParamValue(wxT("family"));
1605 if (family == wxT("decorative")) ifamily = wxDECORATIVE;
1606 else if (family == wxT("roman")) ifamily = wxROMAN;
1607 else if (family == wxT("script")) ifamily = wxSCRIPT;
1608 else if (family == wxT("swiss")) ifamily = wxSWISS;
1609 else if (family == wxT("modern")) ifamily = wxMODERN;
1610 else if (family == wxT("teletype")) ifamily = wxTELETYPE;
1611 }
e7a3a5a5
WS
1612
1613
1df61962
VS
1614 wxString facename;
1615 bool hasFacename = HasParam(wxT("face"));
1616 if (hasFacename)
1617 {
1618 wxString faces = GetParamValue(wxT("face"));
1df61962 1619 wxStringTokenizer tk(faces, wxT(","));
63feebce
VS
1620#if wxUSE_FONTENUM
1621 wxArrayString facenames(wxFontEnumerator::GetFacenames());
1df61962 1622 while (tk.HasMoreTokens())
78d14f80 1623 {
6540132f 1624 int index = facenames.Index(tk.GetNextToken(), false);
1df61962
VS
1625 if (index != wxNOT_FOUND)
1626 {
6540132f 1627 facename = facenames[index];
1df61962
VS
1628 break;
1629 }
78d14f80 1630 }
63feebce
VS
1631#else // !wxUSE_FONTENUM
1632 // just use the first face name if we can't check its availability:
1633 if (tk.HasMoreTokens())
1634 facename = tk.GetNextToken();
1635#endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
78d14f80
VS
1636 }
1637
1df61962
VS
1638 // encoding
1639 wxFontEncoding enc = wxFONTENCODING_DEFAULT;
1640 bool hasEncoding = HasParam(wxT("encoding"));
1641 if (hasEncoding)
1642 {
1643 wxString encoding = GetParamValue(wxT("encoding"));
1644 wxFontMapper mapper;
e7a3a5a5 1645 if (!encoding.empty())
1df61962
VS
1646 enc = mapper.CharsetToEncoding(encoding);
1647 if (enc == wxFONTENCODING_SYSTEM)
1648 enc = wxFONTENCODING_DEFAULT;
1649 }
78d14f80 1650
1df61962 1651 // is this font based on a system font?
94245f6d 1652 wxFont font = GetSystemFont(GetParamValue(wxT("sysfont")));
e7a3a5a5 1653
94245f6d 1654 if (font.Ok())
1df61962 1655 {
94245f6d
VZ
1656 if (hasSize && isize != -1)
1657 font.SetPointSize(isize);
1df61962 1658 else if (HasParam(wxT("relativesize")))
94245f6d 1659 font.SetPointSize(int(font.GetPointSize() *
1df61962 1660 GetFloat(wxT("relativesize"))));
e7a3a5a5 1661
1df61962 1662 if (hasStyle)
94245f6d 1663 font.SetStyle(istyle);
1df61962 1664 if (hasWeight)
94245f6d 1665 font.SetWeight(iweight);
1df61962 1666 if (hasUnderlined)
94245f6d 1667 font.SetUnderlined(underlined);
1df61962 1668 if (hasFamily)
94245f6d 1669 font.SetFamily(ifamily);
1df61962 1670 if (hasFacename)
94245f6d 1671 font.SetFaceName(facename);
1df61962 1672 if (hasEncoding)
94245f6d
VZ
1673 font.SetDefaultEncoding(enc);
1674 }
1675 else // not based on system font
1676 {
1677 font = wxFont(isize == -1 ? wxNORMAL_FONT->GetPointSize() : isize,
1678 ifamily, istyle, iweight,
1679 underlined, facename, enc);
1df61962 1680 }
8516a98b
DS
1681
1682 m_node = oldnode;
94245f6d 1683 return font;
78d14f80
VS
1684}
1685
1686
1687void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
1688{
1689 //FIXME : add cursor
1690
1691 if (HasParam(wxT("exstyle")))
0099f343
JS
1692 // Have to OR it with existing style, since
1693 // some implementations (e.g. wxGTK) use the extra style
1694 // during creation
1695 wnd->SetExtraStyle(wnd->GetExtraStyle() | GetStyle(wxT("exstyle")));
78d14f80
VS
1696 if (HasParam(wxT("bg")))
1697 wnd->SetBackgroundColour(GetColour(wxT("bg")));
1698 if (HasParam(wxT("fg")))
1699 wnd->SetForegroundColour(GetColour(wxT("fg")));
1700 if (GetBool(wxT("enabled"), 1) == 0)
f80ea77b 1701 wnd->Enable(false);
78d14f80
VS
1702 if (GetBool(wxT("focused"), 0) == 1)
1703 wnd->SetFocus();
1704 if (GetBool(wxT("hidden"), 0) == 1)
f80ea77b 1705 wnd->Show(false);
78d14f80
VS
1706#if wxUSE_TOOLTIPS
1707 if (HasParam(wxT("tooltip")))
1708 wnd->SetToolTip(GetText(wxT("tooltip")));
1709#endif
1710 if (HasParam(wxT("font")))
1711 wnd->SetFont(GetFont());
b23030d6
JS
1712 if (HasParam(wxT("help")))
1713 wnd->SetHelpText(GetText(wxT("help")));
78d14f80
VS
1714}
1715
1716
1717void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
1718{
23239d94 1719 for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() )
78d14f80 1720 {
23239d94 1721 if ( IsObjectNode(n) )
78d14f80 1722 {
317a0d73
VS
1723 m_resource->CreateResFromNode(n, parent, NULL,
1724 this_hnd_only ? this : NULL);
78d14f80 1725 }
78d14f80
VS
1726 }
1727}
1728
1729
1730void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode)
1731{
1732 wxXmlNode *root;
1733 if (rootnode == NULL) root = m_node; else root = rootnode;
1734 wxXmlNode *n = root->GetChildren();
1735
1736 while (n)
1737 {
1738 if (n->GetType() == wxXML_ELEMENT_NODE && CanHandle(n))
1739 {
1740 CreateResource(n, parent, NULL);
1741 }
1742 n = n->GetNext();
1743 }
1744}
1745
1746
819559b2
VS
1747//-----------------------------------------------------------------------------
1748// errors reporting
1749//-----------------------------------------------------------------------------
1750
1751void wxXmlResourceHandler::ReportError(const wxString& message)
1752{
1753 m_resource->ReportError(m_node, message);
1754}
1755
1756void wxXmlResourceHandler::ReportError(wxXmlNode *context,
1757 const wxString& message)
1758{
1759 m_resource->ReportError(context ? context : m_node, message);
1760}
1761
1762void wxXmlResourceHandler::ReportParamError(const wxString& param,
1763 const wxString& message)
1764{
1765 m_resource->ReportError(GetParamNode(param), message);
1766}
1767
1768namespace
1769{
1770
1771wxString
1772GetFileNameFromNode(wxXmlNode *node, const wxXmlResourceDataRecords& files)
1773{
1774 wxXmlNode *root = node;
1775 while ( root->GetParent() )
1776 root = root->GetParent();
1777
1778 for ( wxXmlResourceDataRecords::const_iterator i = files.begin();
1779 i != files.end(); ++i )
1780 {
1781 if ( (*i)->Doc->GetRoot() == root )
1782 {
1783 return (*i)->File;
1784 }
1785 }
1786
1787 return wxEmptyString; // not found
1788}
1789
1790} // anonymous namespace
1791
1792void wxXmlResource::ReportError(wxXmlNode *context, const wxString& message)
1793{
1794 if ( !context )
1795 {
1796 DoReportError("", NULL, message);
1797 return;
1798 }
78d14f80 1799
819559b2
VS
1800 // We need to find out the file that 'context' is part of. Performance of
1801 // this code is not critical, so we simply find the root XML node and
1802 // compare it with all loaded XRC files.
1803 const wxString filename = GetFileNameFromNode(context, Data());
78d14f80 1804
819559b2
VS
1805 DoReportError(filename, context, message);
1806}
78d14f80 1807
819559b2
VS
1808void wxXmlResource::DoReportError(const wxString& xrcFile, wxXmlNode *position,
1809 const wxString& message)
1810{
1811 const int line = position ? position->GetLineNumber() : -1;
1812
1813 wxString loc;
1814 if ( !xrcFile.empty() )
1815 loc = xrcFile + ':';
1816 if ( line != -1 )
1817 loc += wxString::Format("%d:", line);
1818 if ( !loc.empty() )
1819 loc += ' ';
1820
1821 wxLogError("XRC error: %s%s", loc, message);
1822}
78d14f80
VS
1823
1824
819559b2
VS
1825//-----------------------------------------------------------------------------
1826// XRCID implementation
1827//-----------------------------------------------------------------------------
78d14f80 1828
5ed345b7 1829#define XRCID_TABLE_SIZE 1024
78d14f80
VS
1830
1831
5ed345b7 1832struct XRCID_record
78d14f80 1833{
cf2810aa
VZ
1834 /* Hold the id so that once an id is allocated for a name, it
1835 does not get created again by NewControlId at least
1836 until we are done with it */
1837 wxWindowIDRef id;
c560da98 1838 char *key;
5ed345b7 1839 XRCID_record *next;
78d14f80
VS
1840};
1841
5ed345b7 1842static XRCID_record *XRCID_Records[XRCID_TABLE_SIZE] = {NULL};
78d14f80 1843
c560da98 1844static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE)
78d14f80 1845{
78d14f80
VS
1846 int index = 0;
1847
c560da98 1848 for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
5ed345b7 1849 index %= XRCID_TABLE_SIZE;
78d14f80 1850
5ed345b7 1851 XRCID_record *oldrec = NULL;
5ed345b7 1852 for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
78d14f80 1853 {
00393283 1854 if (wxStrcmp(rec->key, str_id) == 0)
78d14f80
VS
1855 {
1856 return rec->id;
1857 }
78d14f80
VS
1858 oldrec = rec;
1859 }
1860
5ed345b7
VS
1861 XRCID_record **rec_var = (oldrec == NULL) ?
1862 &XRCID_Records[index] : &oldrec->next;
1863 *rec_var = new XRCID_record;
00393283 1864 (*rec_var)->key = wxStrdup(str_id);
78d14f80
VS
1865 (*rec_var)->next = NULL;
1866
c560da98 1867 char *end;
9b2a7469 1868 if (value_if_not_found != wxID_NONE)
13de23f6 1869 (*rec_var)->id = value_if_not_found;
85452d74
VS
1870 else
1871 {
13de23f6
VS
1872 int asint = wxStrtol(str_id, &end, 10);
1873 if (*str_id && *end == 0)
1874 {
1875 // if str_id was integer, keep it verbosely:
1876 (*rec_var)->id = asint;
1877 }
1878 else
1879 {
f35fdf7e 1880 (*rec_var)->id = wxWindowBase::NewControlId();
13de23f6 1881 }
85452d74
VS
1882 }
1883
78d14f80
VS
1884 return (*rec_var)->id;
1885}
1886
3b2a000e
VS
1887static void AddStdXRCID_Records();
1888
9b2a7469 1889/*static*/
c560da98 1890int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found)
13de23f6 1891{
3b2a000e
VS
1892 static bool s_stdIDsAdded = false;
1893
1894 if ( !s_stdIDsAdded )
1895 {
1896 s_stdIDsAdded = true;
1897 AddStdXRCID_Records();
1898 }
1899
9b2a7469 1900 return XRCID_Lookup(str_id, value_if_not_found);
13de23f6
VS
1901}
1902
cc378c2d
VZ
1903/* static */
1904wxString wxXmlResource::FindXRCIDById(int numId)
1905{
1906 for ( int i = 0; i < XRCID_TABLE_SIZE; i++ )
1907 {
1908 for ( XRCID_record *rec = XRCID_Records[i]; rec; rec = rec->next )
1909 {
1910 if ( rec->id == numId )
1911 return wxString(rec->key);
1912 }
1913 }
1914
1915 return wxString();
1916}
78d14f80 1917
5ed345b7 1918static void CleanXRCID_Record(XRCID_record *rec)
78d14f80
VS
1919{
1920 if (rec)
1921 {
5ed345b7 1922 CleanXRCID_Record(rec->next);
f35fdf7e 1923
00393283 1924 free(rec->key);
78d14f80
VS
1925 delete rec;
1926 }
1927}
1928
5ed345b7 1929static void CleanXRCID_Records()
78d14f80 1930{
5ed345b7 1931 for (int i = 0; i < XRCID_TABLE_SIZE; i++)
139c5871 1932 {
5ed345b7 1933 CleanXRCID_Record(XRCID_Records[i]);
139c5871
VS
1934 XRCID_Records[i] = NULL;
1935 }
78d14f80
VS
1936}
1937
13de23f6
VS
1938static void AddStdXRCID_Records()
1939{
c560da98 1940#define stdID(id) XRCID_Lookup(#id, id)
13de23f6 1941 stdID(-1);
c369d4f1
VS
1942
1943 stdID(wxID_ANY);
1944 stdID(wxID_SEPARATOR);
e7a3a5a5 1945
c369d4f1
VS
1946 stdID(wxID_OPEN);
1947 stdID(wxID_CLOSE);
1948 stdID(wxID_NEW);
1949 stdID(wxID_SAVE);
1950 stdID(wxID_SAVEAS);
1951 stdID(wxID_REVERT);
1952 stdID(wxID_EXIT);
1953 stdID(wxID_UNDO);
1954 stdID(wxID_REDO);
1955 stdID(wxID_HELP);
1956 stdID(wxID_PRINT);
1957 stdID(wxID_PRINT_SETUP);
e63f19ba 1958 stdID(wxID_PAGE_SETUP);
c369d4f1
VS
1959 stdID(wxID_PREVIEW);
1960 stdID(wxID_ABOUT);
1961 stdID(wxID_HELP_CONTENTS);
1962 stdID(wxID_HELP_COMMANDS);
1963 stdID(wxID_HELP_PROCEDURES);
1964 stdID(wxID_HELP_CONTEXT);
13de23f6 1965 stdID(wxID_CLOSE_ALL);
c369d4f1 1966 stdID(wxID_PREFERENCES);
d73195fd 1967 stdID(wxID_EDIT);
c369d4f1
VS
1968 stdID(wxID_CUT);
1969 stdID(wxID_COPY);
1970 stdID(wxID_PASTE);
1971 stdID(wxID_CLEAR);
1972 stdID(wxID_FIND);
1973 stdID(wxID_DUPLICATE);
1974 stdID(wxID_SELECTALL);
1975 stdID(wxID_DELETE);
1976 stdID(wxID_REPLACE);
1977 stdID(wxID_REPLACE_ALL);
1978 stdID(wxID_PROPERTIES);
1979 stdID(wxID_VIEW_DETAILS);
1980 stdID(wxID_VIEW_LARGEICONS);
1981 stdID(wxID_VIEW_SMALLICONS);
1982 stdID(wxID_VIEW_LIST);
1983 stdID(wxID_VIEW_SORTDATE);
1984 stdID(wxID_VIEW_SORTNAME);
1985 stdID(wxID_VIEW_SORTSIZE);
1986 stdID(wxID_VIEW_SORTTYPE);
1987 stdID(wxID_FILE1);
1988 stdID(wxID_FILE2);
1989 stdID(wxID_FILE3);
1990 stdID(wxID_FILE4);
1991 stdID(wxID_FILE5);
1992 stdID(wxID_FILE6);
1993 stdID(wxID_FILE7);
1994 stdID(wxID_FILE8);
1995 stdID(wxID_FILE9);
1996 stdID(wxID_OK);
1997 stdID(wxID_CANCEL);
1998 stdID(wxID_APPLY);
1999 stdID(wxID_YES);
2000 stdID(wxID_NO);
2001 stdID(wxID_STATIC);
2002 stdID(wxID_FORWARD);
2003 stdID(wxID_BACKWARD);
2004 stdID(wxID_DEFAULT);
2005 stdID(wxID_MORE);
2006 stdID(wxID_SETUP);
2007 stdID(wxID_RESET);
2008 stdID(wxID_CONTEXT_HELP);
2009 stdID(wxID_YESTOALL);
2010 stdID(wxID_NOTOALL);
2011 stdID(wxID_ABORT);
2012 stdID(wxID_RETRY);
2013 stdID(wxID_IGNORE);
2014 stdID(wxID_ADD);
2015 stdID(wxID_REMOVE);
2016 stdID(wxID_UP);
2017 stdID(wxID_DOWN);
2018 stdID(wxID_HOME);
2019 stdID(wxID_REFRESH);
2020 stdID(wxID_STOP);
2021 stdID(wxID_INDEX);
2022 stdID(wxID_BOLD);
2023 stdID(wxID_ITALIC);
2024 stdID(wxID_JUSTIFY_CENTER);
2025 stdID(wxID_JUSTIFY_FILL);
2026 stdID(wxID_JUSTIFY_RIGHT);
2027 stdID(wxID_JUSTIFY_LEFT);
2028 stdID(wxID_UNDERLINE);
2029 stdID(wxID_INDENT);
2030 stdID(wxID_UNINDENT);
2031 stdID(wxID_ZOOM_100);
2032 stdID(wxID_ZOOM_FIT);
2033 stdID(wxID_ZOOM_IN);
2034 stdID(wxID_ZOOM_OUT);
2035 stdID(wxID_UNDELETE);
2036 stdID(wxID_REVERT_TO_SAVED);
2037 stdID(wxID_SYSTEM_MENU);
2038 stdID(wxID_CLOSE_FRAME);
2039 stdID(wxID_MOVE_FRAME);
2040 stdID(wxID_RESIZE_FRAME);
2041 stdID(wxID_MAXIMIZE_FRAME);
2042 stdID(wxID_ICONIZE_FRAME);
2043 stdID(wxID_RESTORE_FRAME);
6b1eedc1
VZ
2044 stdID(wxID_CDROM);
2045 stdID(wxID_CONVERT);
2046 stdID(wxID_EXECUTE);
2047 stdID(wxID_FLOPPY);
2048 stdID(wxID_HARDDISK);
2049 stdID(wxID_BOTTOM);
2050 stdID(wxID_FIRST);
2051 stdID(wxID_LAST);
2052 stdID(wxID_TOP);
2053 stdID(wxID_INFO);
2054 stdID(wxID_JUMP_TO);
2055 stdID(wxID_NETWORK);
2056 stdID(wxID_SELECT_COLOR);
2057 stdID(wxID_SELECT_FONT);
2058 stdID(wxID_SORT_ASCENDING);
2059 stdID(wxID_SORT_DESCENDING);
2060 stdID(wxID_SPELL_CHECK);
2061 stdID(wxID_STRIKETHROUGH);
c369d4f1 2062
13de23f6
VS
2063#undef stdID
2064}
78d14f80
VS
2065
2066
2067
2068
2069
819559b2
VS
2070//-----------------------------------------------------------------------------
2071// module and globals
2072//-----------------------------------------------------------------------------
78d14f80 2073
fd230129
VZ
2074// normally we would do the cleanup from wxXmlResourceModule::OnExit() but it
2075// can happen that some XRC records have been created because of the use of
2076// XRCID() in event tables, which happens during static objects initialization,
2077// but then the application initialization failed and so the wx modules were
2078// neither initialized nor cleaned up -- this static object does the cleanup in
2079// this case
2080static struct wxXRCStaticCleanup
2081{
2082 ~wxXRCStaticCleanup() { CleanXRCID_Records(); }
2083} s_staticCleanup;
2084
78d14f80
VS
2085class wxXmlResourceModule: public wxModule
2086{
2087DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
2088public:
2089 wxXmlResourceModule() {}
824e8eaa
VS
2090 bool OnInit()
2091 {
2b5f62a0 2092 wxXmlResource::AddSubclassFactory(new wxXmlSubclassFactoryCXX);
f80ea77b 2093 return true;
824e8eaa 2094 }
78d14f80
VS
2095 void OnExit()
2096 {
1542c42e 2097 delete wxXmlResource::Set(NULL);
461932ae 2098 if(wxXmlResource::ms_subclassFactories)
eb2d0d23
VS
2099 {
2100 for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
2101 i != wxXmlResource::ms_subclassFactories->end(); ++i )
2102 {
2103 delete *i;
2104 }
2105 wxDELETE(wxXmlResource::ms_subclassFactories);
2106 }
5ed345b7 2107 CleanXRCID_Records();
78d14f80
VS
2108 }
2109};
2110
2111IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)
2112
2113
2114// When wxXml is loaded dynamically after the application is already running
2115// then the built-in module system won't pick this one up. Add it manually.
2116void wxXmlInitResourceModule()
2117{
2118 wxModule* module = new wxXmlResourceModule;
2119 module->Init();
2120 wxModule::RegisterModule(module);
2121}
a1e4ec87
VS
2122
2123#endif // wxUSE_XRC