]> git.saurik.com Git - wxWidgets.git/blame - src/xrc/xmlres.cpp
Don't consider extra ".." an error in wxFileName::Normalize().
[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"
326462ae 47#include "wx/imaglist.h"
2bb9a404 48#include "wx/dir.h"
34c6bbee 49#include "wx/xml/xml.h"
0526c8cc 50#include "wx/hashset.h"
78d14f80 51
f35fdf7e 52
eb2d0d23
VS
53class wxXmlResourceDataRecord
54{
55public:
56 wxXmlResourceDataRecord() : Doc(NULL) {
57#if wxUSE_DATETIME
58 Time = wxDateTime::Now();
59#endif
60 }
61 ~wxXmlResourceDataRecord() {delete Doc;}
62
63 wxString File;
64 wxXmlDocument *Doc;
65#if wxUSE_DATETIME
66 wxDateTime Time;
67#endif
68};
69
f396e5a7 70class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord*>
eb2d0d23
VS
71{
72 // this is a class so that it can be forward-declared
73};
78d14f80 74
0526c8cc
VZ
75WX_DECLARE_HASH_SET(int, wxIntegerHash, wxIntegerEqual, wxHashSetInt);
76
77class wxIdRange // Holds data for a particular rangename
78{
79protected:
80 wxIdRange(const wxXmlNode* node,
81 const wxString& rname,
82 const wxString& startno,
83 const wxString& rsize);
84
85 // Note the existence of an item within the range
86 void NoteItem(const wxXmlNode* node, const wxString& item);
87
88 // The manager is telling us that it's finished adding items
89 void Finalise(const wxXmlNode* node);
90
91 wxString GetName() const { return m_name; }
92 bool IsFinalised() const { return m_finalised; }
93
94 const wxString m_name;
95 int m_start;
96 int m_end;
97 unsigned int m_size;
98 bool m_item_end_found;
99 bool m_finalised;
100 wxHashSetInt m_indices;
101
102 friend class wxIdRangeManager;
103};
104
105class wxIdRangeManager
106{
107public:
108 ~wxIdRangeManager();
109 // Gets the global resources object or creates one if none exists.
110 static wxIdRangeManager *Get();
111
112 // Sets the global resources object and returns a pointer to the previous
113 // one (may be NULL).
114 static wxIdRangeManager *Set(wxIdRangeManager *res);
115
116 // Create a new IDrange from this node
117 void AddRange(const wxXmlNode* node);
118 // Tell the IdRange that this item exists, and should be pre-allocated an ID
119 void NotifyRangeOfItem(const wxXmlNode* node, const wxString& item) const;
120 // Tells all IDranges that they're now complete, and can create their IDs
121 void FinaliseRanges(const wxXmlNode* node) const;
122 // Searches for a known IdRange matching 'name', returning its index or -1
123 int Find(const wxString& rangename) const;
124 // Removes, if it exists, an entry from the XRCID table. Used in id-ranges
125 // to replace defunct or statically-initialised entries with current values
e7cad4b7 126 static void RemoveXRCIDEntry(const wxString& idstr);
0526c8cc
VZ
127
128protected:
129 wxIdRange* FindRangeForItem(const wxXmlNode* node,
130 const wxString& item,
131 wxString& value) const;
132 wxVector<wxIdRange*> m_IdRanges;
133
134private:
135 static wxIdRangeManager *ms_instance;
136};
137
23239d94
VZ
138namespace
139{
140
141// helper used by DoFindResource() and elsewhere: returns true if this is an
142// object or object_ref node
143//
144// node must be non-NULL
145inline bool IsObjectNode(wxXmlNode *node)
146{
147 return node->GetType() == wxXML_ELEMENT_NODE &&
148 (node->GetName() == wxS("object") ||
149 node->GetName() == wxS("object_ref"));
150}
151
a1eeda0b
VS
152// special XML attribute with name of input file, see GetFileNameFromNode()
153const char *ATTR_INPUT_FILENAME = "__wx:filename";
154
155// helper to get filename corresponding to an XML node
156wxString
1f6ea935 157GetFileNameFromNode(const wxXmlNode *node, const wxXmlResourceDataRecords& files)
a1eeda0b
VS
158{
159 // this loop does two things: it looks for ATTR_INPUT_FILENAME among
160 // parents and if it isn't used, it finds the root of the XML tree 'node'
161 // is in
162 for ( ;; )
163 {
164 // in some rare cases (specifically, when an <object_ref> is used, see
165 // wxXmlResource::CreateResFromNode() and MergeNodesOver()), we work
166 // with XML nodes that are not rooted in any document from 'files'
167 // (because a new node was created by CreateResFromNode() to merge the
168 // content of <object_ref> and the referenced <object>); in that case,
169 // we hack around the problem by putting the information about input
170 // file into a custom attribute
171 if ( node->HasAttribute(ATTR_INPUT_FILENAME) )
172 return node->GetAttribute(ATTR_INPUT_FILENAME);
173
174 if ( !node->GetParent() )
175 break; // we found the root of this XML tree
176
177 node = node->GetParent();
178 }
179
180 // NB: 'node' now points to the root of XML document
181
182 for ( wxXmlResourceDataRecords::const_iterator i = files.begin();
183 i != files.end(); ++i )
184 {
185 if ( (*i)->Doc->GetRoot() == node )
186 {
187 return (*i)->File;
188 }
189 }
190
191 return wxEmptyString; // not found
192}
193
23239d94
VZ
194} // anonymous namespace
195
78d14f80 196
824e8eaa
VS
197wxXmlResource *wxXmlResource::ms_instance = NULL;
198
199/*static*/ wxXmlResource *wxXmlResource::Get()
200{
201 if ( !ms_instance )
202 ms_instance = new wxXmlResource;
203 return ms_instance;
204}
205
206/*static*/ wxXmlResource *wxXmlResource::Set(wxXmlResource *res)
207{
208 wxXmlResource *old = ms_instance;
209 ms_instance = res;
210 return old;
211}
212
d4a724d4 213wxXmlResource::wxXmlResource(int flags, const wxString& domain)
78d14f80 214{
daa85ee3 215 m_flags = flags;
78d14f80 216 m_version = -1;
eb2d0d23 217 m_data = new wxXmlResourceDataRecords;
d7a80cf5 218 SetDomain(domain);
78d14f80
VS
219}
220
d4a724d4 221wxXmlResource::wxXmlResource(const wxString& filemask, int flags, const wxString& domain)
78d14f80 222{
daa85ee3 223 m_flags = flags;
78d14f80 224 m_version = -1;
eb2d0d23 225 m_data = new wxXmlResourceDataRecords;
d7a80cf5 226 SetDomain(domain);
78d14f80
VS
227 Load(filemask);
228}
229
230wxXmlResource::~wxXmlResource()
231{
232 ClearHandlers();
eb2d0d23 233
f396e5a7
VS
234 for ( wxXmlResourceDataRecords::iterator i = m_data->begin();
235 i != m_data->end(); ++i )
236 {
237 delete *i;
238 }
eb2d0d23 239 delete m_data;
78d14f80
VS
240}
241
d7a80cf5 242void wxXmlResource::SetDomain(const wxString& domain)
d4a724d4 243{
d7a80cf5 244 m_domain = domain;
d4a724d4
RD
245}
246
78d14f80 247
60fd818a
VZ
248/* static */
249wxString wxXmlResource::ConvertFileNameToURL(const wxString& filename)
250{
251 wxString fnd(filename);
252
253 // NB: as Load() and Unload() accept both filenames and URLs (should
254 // probably be changed to filenames only, but embedded resources
255 // currently rely on its ability to handle URLs - FIXME) we need to
256 // determine whether found name is filename and not URL and this is the
257 // fastest/simplest way to do it
258 if (wxFileName::FileExists(fnd))
259 {
260 // Make the name absolute filename, because the app may
261 // change working directory later:
262 wxFileName fn(fnd);
263 if (fn.IsRelative())
264 {
265 fn.MakeAbsolute();
266 fnd = fn.GetFullPath();
267 }
268#if wxUSE_FILESYSTEM
269 fnd = wxFileSystem::FileNameToURL(fnd);
270#endif
271 }
272
273 return fnd;
274}
275
276#if wxUSE_FILESYSTEM
277
278/* static */
279bool wxXmlResource::IsArchive(const wxString& filename)
280{
281 const wxString fnd = filename.Lower();
282
283 return fnd.Matches(wxT("*.zip")) || fnd.Matches(wxT("*.xrs"));
284}
285
286#endif // wxUSE_FILESYSTEM
287
04ae32cd
VS
288bool wxXmlResource::LoadFile(const wxFileName& file)
289{
159852ae 290#if wxUSE_FILESYSTEM
04ae32cd 291 return Load(wxFileSystem::FileNameToURL(file));
159852ae
VS
292#else
293 return Load(file.GetFullPath());
294#endif
04ae32cd
VS
295}
296
2bb9a404
VS
297bool wxXmlResource::LoadAllFiles(const wxString& dirname)
298{
299 bool ok = true;
300 wxArrayString files;
301
302 wxDir::GetAllFiles(dirname, &files, "*.xrc");
303
304 for ( wxArrayString::const_iterator i = files.begin(); i != files.end(); ++i )
305 {
306 if ( !LoadFile(*i) )
307 ok = false;
308 }
309
310 return ok;
311}
312
acd32ffc 313bool wxXmlResource::Load(const wxString& filemask_)
78d14f80 314{
acd32ffc
VS
315 wxString filemask = ConvertFileNameToURL(filemask_);
316
78d14f80
VS
317#if wxUSE_FILESYSTEM
318 wxFileSystem fsys;
319# define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE)
320# define wxXmlFindNext fsys.FindNext()
321#else
322# define wxXmlFindFirst wxFindFirstFile(filemask, wxFILE)
323# define wxXmlFindNext wxFindNextFile()
324#endif
e5bb501b
VZ
325 wxString fnd = wxXmlFindFirst;
326 if ( fnd.empty() )
327 {
328 wxLogError(_("Cannot load resources from '%s'."), filemask);
329 return false;
330 }
331
ec157c8f 332 while (!fnd.empty())
78d14f80
VS
333 {
334#if wxUSE_FILESYSTEM
60fd818a 335 if ( IsArchive(fnd) )
78d14f80 336 {
e5bb501b
VZ
337 if ( !Load(fnd + wxT("#zip:*.xrc")) )
338 return false;
78d14f80 339 }
60fd818a
VZ
340 else // a single resource URL
341#endif // wxUSE_FILESYSTEM
78d14f80 342 {
f396e5a7
VS
343 wxXmlResourceDataRecord *drec = new wxXmlResourceDataRecord;
344 drec->File = fnd;
eb2d0d23 345 Data().push_back(drec);
78d14f80
VS
346 }
347
e5bb501b 348 fnd = wxXmlFindNext;
78d14f80
VS
349 }
350# undef wxXmlFindFirst
351# undef wxXmlFindNext
e5bb501b
VZ
352
353 return UpdateResources();
78d14f80
VS
354}
355
60fd818a
VZ
356bool wxXmlResource::Unload(const wxString& filename)
357{
358 wxASSERT_MSG( !wxIsWild(filename),
9a83f860 359 wxT("wildcards not supported by wxXmlResource::Unload()") );
60fd818a
VZ
360
361 wxString fnd = ConvertFileNameToURL(filename);
362#if wxUSE_FILESYSTEM
363 const bool isArchive = IsArchive(fnd);
364 if ( isArchive )
9a83f860 365 fnd += wxT("#zip:");
60fd818a
VZ
366#endif // wxUSE_FILESYSTEM
367
368 bool unloaded = false;
eb2d0d23
VS
369 for ( wxXmlResourceDataRecords::iterator i = Data().begin();
370 i != Data().end(); ++i )
60fd818a
VZ
371 {
372#if wxUSE_FILESYSTEM
373 if ( isArchive )
374 {
f396e5a7 375 if ( (*i)->File.StartsWith(fnd) )
60fd818a
VZ
376 unloaded = true;
377 // don't break from the loop, we can have other matching files
378 }
379 else // a single resource URL
380#endif // wxUSE_FILESYSTEM
381 {
f396e5a7 382 if ( (*i)->File == fnd )
60fd818a 383 {
f8b1df0b 384 delete *i;
eb2d0d23 385 Data().erase(i);
60fd818a
VZ
386 unloaded = true;
387
388 // no sense in continuing, there is only one file with this URL
389 break;
390 }
391 }
392 }
393
394 return unloaded;
395}
396
78d14f80 397
854e189f 398IMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject)
78d14f80
VS
399
400void wxXmlResource::AddHandler(wxXmlResourceHandler *handler)
401{
eb2d0d23 402 m_handlers.push_back(handler);
78d14f80
VS
403 handler->SetParentResource(this);
404}
405
92e898b0
RD
406void wxXmlResource::InsertHandler(wxXmlResourceHandler *handler)
407{
eb2d0d23 408 m_handlers.insert(m_handlers.begin(), handler);
92e898b0
RD
409 handler->SetParentResource(this);
410}
411
78d14f80
VS
412
413
414void wxXmlResource::ClearHandlers()
415{
eb2d0d23
VS
416 for ( wxVector<wxXmlResourceHandler*>::iterator i = m_handlers.begin();
417 i != m_handlers.end(); ++i )
418 delete *i;
419 m_handlers.clear();
78d14f80
VS
420}
421
422
78d14f80
VS
423wxMenu *wxXmlResource::LoadMenu(const wxString& name)
424{
425 return (wxMenu*)CreateResFromNode(FindResource(name, wxT("wxMenu")), NULL, NULL);
426}
427
428
429
4a1b9596 430wxMenuBar *wxXmlResource::LoadMenuBar(wxWindow *parent, const wxString& name)
78d14f80 431{
4a1b9596 432 return (wxMenuBar*)CreateResFromNode(FindResource(name, wxT("wxMenuBar")), parent, NULL);
78d14f80
VS
433}
434
435
436
4a1b9596 437#if wxUSE_TOOLBAR
78d14f80
VS
438wxToolBar *wxXmlResource::LoadToolBar(wxWindow *parent, const wxString& name)
439{
440 return (wxToolBar*)CreateResFromNode(FindResource(name, wxT("wxToolBar")), parent, NULL);
441}
4a1b9596 442#endif
78d14f80
VS
443
444
445wxDialog *wxXmlResource::LoadDialog(wxWindow *parent, const wxString& name)
446{
4dd75a6a 447 return (wxDialog*)CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, NULL);
78d14f80
VS
448}
449
450bool wxXmlResource::LoadDialog(wxDialog *dlg, wxWindow *parent, const wxString& name)
451{
452 return CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, dlg) != NULL;
453}
454
455
456
457wxPanel *wxXmlResource::LoadPanel(wxWindow *parent, const wxString& name)
458{
459 return (wxPanel*)CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, NULL);
460}
461
462bool wxXmlResource::LoadPanel(wxPanel *panel, wxWindow *parent, const wxString& name)
463{
464 return CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, panel) != NULL;
465}
466
92e898b0
RD
467wxFrame *wxXmlResource::LoadFrame(wxWindow* parent, const wxString& name)
468{
469 return (wxFrame*)CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, NULL);
470}
471
78d14f80
VS
472bool wxXmlResource::LoadFrame(wxFrame* frame, wxWindow *parent, const wxString& name)
473{
474 return CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, frame) != NULL;
475}
476
477wxBitmap wxXmlResource::LoadBitmap(const wxString& name)
478{
479 wxBitmap *bmp = (wxBitmap*)CreateResFromNode(
480 FindResource(name, wxT("wxBitmap")), NULL, NULL);
481 wxBitmap rt;
482
483 if (bmp) { rt = *bmp; delete bmp; }
484 return rt;
485}
486
487wxIcon wxXmlResource::LoadIcon(const wxString& name)
488{
489 wxIcon *icon = (wxIcon*)CreateResFromNode(
490 FindResource(name, wxT("wxIcon")), NULL, NULL);
491 wxIcon rt;
492
493 if (icon) { rt = *icon; delete icon; }
494 return rt;
495}
496
92e898b0 497
af0ac990
VZ
498wxObject *
499wxXmlResource::DoLoadObject(wxWindow *parent,
500 const wxString& name,
501 const wxString& classname,
502 bool recursive)
92e898b0 503{
af0ac990
VZ
504 wxXmlNode * const node = FindResource(name, classname, recursive);
505
506 return node ? DoCreateResFromNode(*node, parent, NULL) : NULL;
92e898b0
RD
507}
508
af0ac990
VZ
509bool
510wxXmlResource::DoLoadObject(wxObject *instance,
511 wxWindow *parent,
512 const wxString& name,
513 const wxString& classname,
514 bool recursive)
92e898b0 515{
af0ac990
VZ
516 wxXmlNode * const node = FindResource(name, classname, recursive);
517
518 return node && DoCreateResFromNode(*node, parent, instance) != NULL;
92e898b0
RD
519}
520
521
78d14f80
VS
522bool wxXmlResource::AttachUnknownControl(const wxString& name,
523 wxWindow *control, wxWindow *parent)
524{
525 if (parent == NULL)
526 parent = control->GetParent();
527 wxWindow *container = parent->FindWindow(name + wxT("_container"));
528 if (!container)
529 {
819559b2 530 wxLogError("Cannot find container for unknown control '%s'.", name);
f80ea77b 531 return false;
78d14f80
VS
532 }
533 return control->Reparent(container);
534}
535
536
77b2f9b1 537static void ProcessPlatformProperty(wxXmlNode *node)
78d14f80
VS
538{
539 wxString s;
540 bool isok;
541
542 wxXmlNode *c = node->GetChildren();
543 while (c)
544 {
f80ea77b 545 isok = false;
288b6107 546 if (!c->GetAttribute(wxT("platform"), &s))
f80ea77b 547 isok = true;
78d14f80
VS
548 else
549 {
2b5f62a0 550 wxStringTokenizer tkn(s, wxT(" |"));
78d14f80
VS
551
552 while (tkn.HasMoreTokens())
553 {
554 s = tkn.GetNextToken();
84389518 555#ifdef __WINDOWS__
d003330c
VS
556 if (s == wxT("win")) isok = true;
557#endif
b380439d 558#if defined(__MAC__) || defined(__APPLE__)
d003330c 559 if (s == wxT("mac")) isok = true;
b380439d
RD
560#elif defined(__UNIX__)
561 if (s == wxT("unix")) isok = true;
78d14f80 562#endif
d003330c
VS
563#ifdef __OS2__
564 if (s == wxT("os2")) isok = true;
565#endif
566
567 if (isok)
568 break;
78d14f80
VS
569 }
570 }
571
572 if (isok)
d7b1d73c 573 {
78d14f80 574 ProcessPlatformProperty(c);
d7b1d73c
VS
575 c = c->GetNext();
576 }
78d14f80
VS
577 else
578 {
d7b1d73c 579 wxXmlNode *c2 = c->GetNext();
db59a97c 580 node->RemoveChild(c);
78d14f80 581 delete c;
d7b1d73c 582 c = c2;
78d14f80 583 }
78d14f80
VS
584 }
585}
586
0526c8cc
VZ
587static void PreprocessForIdRanges(wxXmlNode *rootnode)
588{
589 // First go through the top level, looking for the names of ID ranges
590 // as processing items is a lot easier if names are already known
591 wxXmlNode *c = rootnode->GetChildren();
592 while (c)
593 {
594 if (c->GetName() == wxT("ids-range"))
595 wxIdRangeManager::Get()->AddRange(c);
596 c = c->GetNext();
597 }
598
599 // Next, examine every 'name' for the '[' that denotes an ID in a range
600 c = rootnode->GetChildren();
601 while (c)
602 {
603 wxString name = c->GetAttribute(wxT("name"));
604 if (name.find('[') != wxString::npos)
605 wxIdRangeManager::Get()->NotifyRangeOfItem(rootnode, name);
78d14f80 606
0526c8cc
VZ
607 // Do any children by recursion, then proceed to the next sibling
608 PreprocessForIdRanges(c);
609 c = c->GetNext();
610 }
611}
78d14f80 612
d614f51b 613bool wxXmlResource::UpdateResources()
78d14f80 614{
d614f51b 615 bool rt = true;
78d14f80
VS
616 bool modif;
617# if wxUSE_FILESYSTEM
618 wxFSFile *file = NULL;
19d0f58d 619 wxUnusedVar(file);
78d14f80
VS
620 wxFileSystem fsys;
621# endif
622
480505bc
VS
623 wxString encoding(wxT("UTF-8"));
624#if !wxUSE_UNICODE && wxUSE_INTL
625 if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 )
626 {
75d38380
VS
627 // In case we are not using wxLocale to translate strings, convert the
628 // strings GUI's charset. This must not be done when wxXRC_USE_LOCALE
629 // is on, because it could break wxGetTranslation lookup.
480505bc
VS
630 encoding = wxLocale::GetSystemEncodingName();
631 }
632#endif
633
eb2d0d23
VS
634 for ( wxXmlResourceDataRecords::iterator i = Data().begin();
635 i != Data().end(); ++i )
78d14f80 636 {
f396e5a7
VS
637 wxXmlResourceDataRecord* const rec = *i;
638
639 modif = (rec->Doc == NULL);
78d14f80 640
648db587 641 if (!modif && !(m_flags & wxXRC_NO_RELOADING))
78d14f80
VS
642 {
643# if wxUSE_FILESYSTEM
f396e5a7 644 file = fsys.OpenFile(rec->File);
34af0de4 645# if wxUSE_DATETIME
f396e5a7 646 modif = file && file->GetModificationTime() > rec->Time;
34af0de4
VZ
647# else // wxUSE_DATETIME
648 modif = true;
649# endif // wxUSE_DATETIME
78d14f80 650 if (!file)
d614f51b 651 {
f396e5a7 652 wxLogError(_("Cannot open file '%s'."), rec->File);
d614f51b
VS
653 rt = false;
654 }
78d14f80 655 wxDELETE(file);
19d0f58d 656 wxUnusedVar(file);
34af0de4
VZ
657# else // wxUSE_FILESYSTEM
658# if wxUSE_DATETIME
f396e5a7 659 modif = wxDateTime(wxFileModificationTime(rec->File)) > rec->Time;
34af0de4
VZ
660# else // wxUSE_DATETIME
661 modif = true;
662# endif // wxUSE_DATETIME
663# endif // wxUSE_FILESYSTEM
78d14f80
VS
664 }
665
666 if (modif)
667 {
9a83f860 668 wxLogTrace(wxT("xrc"), wxT("opening file '%s'"), rec->File);
648db587 669
480505bc 670 wxInputStream *stream = NULL;
78d14f80
VS
671
672# if wxUSE_FILESYSTEM
f396e5a7 673 file = fsys.OpenFile(rec->File);
f80ea77b
WS
674 if (file)
675 stream = file->GetStream();
78d14f80 676# else
f396e5a7 677 stream = new wxFileInputStream(rec->File);
78d14f80
VS
678# endif
679
680 if (stream)
681 {
f396e5a7
VS
682 delete rec->Doc;
683 rec->Doc = new wxXmlDocument;
78d14f80 684 }
9690b006 685 if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding))
78d14f80 686 {
480505bc 687 wxLogError(_("Cannot load resources from file '%s'."),
f396e5a7
VS
688 rec->File);
689 wxDELETE(rec->Doc);
d614f51b 690 rt = false;
78d14f80 691 }
f396e5a7 692 else if (rec->Doc->GetRoot()->GetName() != wxT("resource"))
78d14f80 693 {
819559b2
VS
694 ReportError
695 (
696 rec->Doc->GetRoot(),
697 "invalid XRC resource, doesn't have root node <resource>"
698 );
f396e5a7 699 wxDELETE(rec->Doc);
d614f51b 700 rt = false;
78d14f80
VS
701 }
702 else
f80ea77b 703 {
78d14f80
VS
704 long version;
705 int v1, v2, v3, v4;
f396e5a7 706 wxString verstr = rec->Doc->GetRoot()->GetAttribute(
78d14f80
VS
707 wxT("version"), wxT("0.0.0.0"));
708 if (wxSscanf(verstr.c_str(), wxT("%i.%i.%i.%i"),
709 &v1, &v2, &v3, &v4) == 4)
710 version = v1*256*256*256+v2*256*256+v3*256+v4;
711 else
712 version = 0;
713 if (m_version == -1)
714 m_version = version;
715 if (m_version != version)
d614f51b 716 {
819559b2 717 wxLogError("Resource files must have same version number.");
d614f51b
VS
718 rt = false;
719 }
78d14f80 720
f396e5a7 721 ProcessPlatformProperty(rec->Doc->GetRoot());
0526c8cc
VZ
722 PreprocessForIdRanges(rec->Doc->GetRoot());
723 wxIdRangeManager::Get()->FinaliseRanges(rec->Doc->GetRoot());
34af0de4 724#if wxUSE_DATETIME
496f0a58 725#if wxUSE_FILESYSTEM
f396e5a7 726 rec->Time = file->GetModificationTime();
34af0de4 727#else // wxUSE_FILESYSTEM
f396e5a7 728 rec->Time = wxDateTime(wxFileModificationTime(rec->File));
34af0de4
VZ
729#endif // wxUSE_FILESYSTEM
730#endif // wxUSE_DATETIME
f80ea77b 731 }
78d14f80
VS
732
733# if wxUSE_FILESYSTEM
f80ea77b
WS
734 wxDELETE(file);
735 wxUnusedVar(file);
78d14f80 736# else
f80ea77b 737 wxDELETE(stream);
78d14f80
VS
738# endif
739 }
740 }
d614f51b
VS
741
742 return rt;
78d14f80
VS
743}
744
b272b6dc
RD
745wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,
746 const wxString& name,
747 const wxString& classname,
23239d94 748 bool recursive) const
47793ab8 749{
47793ab8
VS
750 wxXmlNode *node;
751
752 // first search for match at the top-level nodes (as this is
753 // where the resource is most commonly looked for):
754 for (node = parent->GetChildren(); node; node = node->GetNext())
755 {
23239d94 756 if ( IsObjectNode(node) && node->GetAttribute(wxS("name")) == name )
2b5f62a0 757 {
23239d94
VZ
758 // empty class name matches everything
759 if ( classname.empty() )
2b5f62a0 760 return node;
23239d94
VZ
761
762 wxString cls(node->GetAttribute(wxS("class")));
763
288b6107 764 // object_ref may not have 'class' attribute:
23239d94 765 if (cls.empty() && node->GetName() == wxS("object_ref"))
2b5f62a0 766 {
23239d94 767 wxString refName = node->GetAttribute(wxS("ref"));
2b5f62a0
VZ
768 if (refName.empty())
769 continue;
23239d94
VZ
770
771 const wxXmlNode * const refNode = GetResourceNode(refName);
772 if ( refNode )
773 cls = refNode->GetAttribute(wxS("class"));
2b5f62a0 774 }
23239d94
VZ
775
776 if ( cls == classname )
777 return node;
2b5f62a0 778 }
47793ab8
VS
779 }
780
23239d94 781 // then recurse in child nodes
47793ab8 782 if ( recursive )
23239d94 783 {
47793ab8
VS
784 for (node = parent->GetChildren(); node; node = node->GetNext())
785 {
23239d94 786 if ( IsObjectNode(node) )
47793ab8 787 {
f80ea77b 788 wxXmlNode* found = DoFindResource(node, name, classname, true);
47793ab8
VS
789 if ( found )
790 return found;
791 }
792 }
23239d94 793 }
47793ab8 794
23239d94 795 return NULL;
47793ab8 796}
78d14f80 797
b272b6dc 798wxXmlNode *wxXmlResource::FindResource(const wxString& name,
47793ab8
VS
799 const wxString& classname,
800 bool recursive)
78d14f80 801{
23239d94
VZ
802 wxString path;
803 wxXmlNode * const
804 node = GetResourceNodeAndLocation(name, classname, recursive, &path);
805
806 if ( !node )
807 {
819559b2
VS
808 ReportError
809 (
810 NULL,
811 wxString::Format
812 (
813 "XRC resource \"%s\" (class \"%s\") not found",
814 name, classname
815 )
816 );
23239d94
VZ
817 }
818#if wxUSE_FILESYSTEM
819 else // node was found
820 {
821 // ensure that relative paths work correctly when loading this node
822 // (which should happen as soon as we return as FindResource() result
823 // is always passed to CreateResFromNode())
824 m_curFileSystem.ChangePathTo(path);
825 }
826#endif // wxUSE_FILESYSTEM
827
828 return node;
829}
830
831wxXmlNode *
832wxXmlResource::GetResourceNodeAndLocation(const wxString& name,
833 const wxString& classname,
834 bool recursive,
835 wxString *path) const
836{
0526c8cc 837 // ensure everything is up-to-date: this is needed to support on-demand
23239d94
VZ
838 // reloading of XRC files
839 const_cast<wxXmlResource *>(this)->UpdateResources();
78d14f80 840
eb2d0d23
VS
841 for ( wxXmlResourceDataRecords::const_iterator f = Data().begin();
842 f != Data().end(); ++f )
78d14f80 843 {
23239d94
VZ
844 wxXmlResourceDataRecord *const rec = *f;
845 wxXmlDocument * const doc = rec->Doc;
846 if ( !doc || !doc->GetRoot() )
47793ab8
VS
847 continue;
848
23239d94
VZ
849 wxXmlNode * const
850 found = DoFindResource(doc->GetRoot(), name, classname, recursive);
47793ab8
VS
851 if ( found )
852 {
23239d94
VZ
853 if ( path )
854 *path = rec->File;
855
47793ab8
VS
856 return found;
857 }
78d14f80
VS
858 }
859
78d14f80
VS
860 return NULL;
861}
862
a1eeda0b
VS
863static void MergeNodesOver(wxXmlNode& dest, wxXmlNode& overwriteWith,
864 const wxString& overwriteFilename)
47793ab8 865{
288b6107 866 // Merge attributes:
a1eeda0b 867 for ( wxXmlAttribute *attr = overwriteWith.GetAttributes();
288b6107 868 attr; attr = attr->GetNext() )
47793ab8 869 {
288b6107
VS
870 wxXmlAttribute *dattr;
871 for (dattr = dest.GetAttributes(); dattr; dattr = dattr->GetNext())
47793ab8 872 {
b272b6dc 873
288b6107 874 if ( dattr->GetName() == attr->GetName() )
47793ab8 875 {
288b6107 876 dattr->SetValue(attr->GetValue());
47793ab8
VS
877 break;
878 }
879 }
78d14f80 880
288b6107
VS
881 if ( !dattr )
882 dest.AddAttribute(attr->GetName(), attr->GetValue());
47793ab8
VS
883 }
884
885 // Merge child nodes:
a1eeda0b 886 for (wxXmlNode* node = overwriteWith.GetChildren(); node; node = node->GetNext())
47793ab8 887 {
288b6107 888 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
47793ab8
VS
889 wxXmlNode *dnode;
890
891 for (dnode = dest.GetChildren(); dnode; dnode = dnode->GetNext() )
892 {
893 if ( dnode->GetName() == node->GetName() &&
288b6107 894 dnode->GetAttribute(wxT("name"), wxEmptyString) == name &&
47793ab8
VS
895 dnode->GetType() == node->GetType() )
896 {
a1eeda0b 897 MergeNodesOver(*dnode, *node, overwriteFilename);
47793ab8
VS
898 break;
899 }
900 }
901
902 if ( !dnode )
b26a650c 903 {
a1eeda0b
VS
904 wxXmlNode *copyOfNode = new wxXmlNode(*node);
905 // remember referenced object's file, see GetFileNameFromNode()
906 copyOfNode->AddAttribute(ATTR_INPUT_FILENAME, overwriteFilename);
907
b26a650c 908 static const wxChar *AT_END = wxT("end");
288b6107 909 wxString insert_pos = node->GetAttribute(wxT("insert_at"), AT_END);
b26a650c
VZ
910 if ( insert_pos == AT_END )
911 {
a1eeda0b 912 dest.AddChild(copyOfNode);
b26a650c
VZ
913 }
914 else if ( insert_pos == wxT("begin") )
915 {
a1eeda0b 916 dest.InsertChild(copyOfNode, dest.GetChildren());
b26a650c
VZ
917 }
918 }
47793ab8
VS
919 }
920
a1eeda0b
VS
921 if ( dest.GetType() == wxXML_TEXT_NODE && overwriteWith.GetContent().length() )
922 dest.SetContent(overwriteWith.GetContent());
47793ab8 923}
78d14f80 924
af0ac990
VZ
925wxObject *
926wxXmlResource::DoCreateResFromNode(wxXmlNode& node,
927 wxObject *parent,
928 wxObject *instance,
929 wxXmlResourceHandler *handlerToUse)
78d14f80 930{
47793ab8 931 // handling of referenced resource
af0ac990 932 if ( node.GetName() == wxT("object_ref") )
47793ab8 933 {
af0ac990 934 wxString refName = node.GetAttribute(wxT("ref"), wxEmptyString);
f80ea77b 935 wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
47793ab8
VS
936
937 if ( !refNode )
938 {
819559b2
VS
939 ReportError
940 (
af0ac990 941 &node,
819559b2
VS
942 wxString::Format
943 (
944 "referenced object node with ref=\"%s\" not found",
945 refName
946 )
947 );
47793ab8
VS
948 return NULL;
949 }
950
af0ac990 951 if ( !node.GetChildren() )
44108a07
VS
952 {
953 // In the typical, simple case, <object_ref> is used to link
954 // to another node and doesn't have any content of its own that
955 // would overwrite linked object's properties. In this case,
956 // we can simply create the resource from linked node.
957
af0ac990 958 return DoCreateResFromNode(*refNode, parent, instance);
44108a07
VS
959 }
960 else
961 {
962 // In the more complicated (but rare) case, <object_ref> has
963 // subnodes that partially overwrite content of the referenced
964 // object. In this case, we need to merge both XML trees and
965 // load the resource from result of the merge.
966
967 wxXmlNode copy(*refNode);
af0ac990 968 MergeNodesOver(copy, node, GetFileNameFromNode(&node, Data()));
a1eeda0b 969
44108a07
VS
970 // remember referenced object's file, see GetFileNameFromNode()
971 copy.AddAttribute(ATTR_INPUT_FILENAME,
972 GetFileNameFromNode(refNode, Data()));
47793ab8 973
af0ac990 974 return DoCreateResFromNode(copy, parent, instance);
44108a07 975 }
47793ab8
VS
976 }
977
317a0d73 978 if (handlerToUse)
b380439d 979 {
af0ac990 980 if (handlerToUse->CanHandle(&node))
8e8a4e85 981 {
af0ac990 982 return handlerToUse->CreateResource(&node, parent, instance);
8e8a4e85 983 }
317a0d73 984 }
af0ac990 985 else if (node.GetName() == wxT("object"))
b380439d 986 {
eb2d0d23
VS
987 for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
988 h != m_handlers.end(); ++h )
317a0d73 989 {
eb2d0d23 990 wxXmlResourceHandler *handler = *h;
af0ac990
VZ
991 if (handler->CanHandle(&node))
992 return handler->CreateResource(&node, parent, instance);
78d14f80 993 }
78d14f80
VS
994 }
995
819559b2
VS
996 ReportError
997 (
af0ac990 998 &node,
819559b2
VS
999 wxString::Format
1000 (
1001 "no handler found for XML node \"%s\" (class \"%s\")",
af0ac990
VZ
1002 node.GetName(),
1003 node.GetAttribute("class", wxEmptyString)
819559b2
VS
1004 )
1005 );
78d14f80
VS
1006 return NULL;
1007}
1008
0526c8cc
VZ
1009wxIdRange::wxIdRange(const wxXmlNode* node,
1010 const wxString& rname,
1011 const wxString& startno,
1012 const wxString& rsize)
1013 : m_name(rname),
1014 m_start(0),
1015 m_size(0),
1016 m_item_end_found(0),
1017 m_finalised(0)
1018{
1019 long l;
1020 if ( startno.ToLong(&l) )
1021 {
1022 if ( l >= 0 )
1023 {
1024 m_start = l;
1025 }
1026 else
1027 {
1028 wxXmlResource::Get()->ReportError
1029 (
1030 node,
1031 "a negative id-range start parameter was given"
1032 );
1033 }
1034 }
1035 else
1036 {
1037 wxXmlResource::Get()->ReportError
1038 (
1039 node,
1040 "the id-range start parameter was malformed"
1041 );
1042 }
1043
1044 unsigned long ul;
1045 if ( rsize.ToULong(&ul) )
1046 {
1047 m_size = ul;
1048 }
1049 else
1050 {
1051 wxXmlResource::Get()->ReportError
1052 (
1053 node,
1054 "the id-range size parameter was malformed"
1055 );
1056 }
1057}
1058
1059void wxIdRange::NoteItem(const wxXmlNode* node, const wxString& item)
1060{
1061 // Nothing gets added here, but the existence of each item is noted
1062 // thus getting an accurate count. 'item' will be either an integer e.g.
1063 // [0] [123]: will eventually create an XRCID as start+integer or [start]
1064 // or [end] which are synonyms for [0] or [range_size-1] respectively.
1065 wxString content(item.Mid(1, item.length()-2));
1066
1067 // Check that basename+item wasn't foo[]
1068 if (content.empty())
1069 {
1070 wxXmlResource::Get()->ReportError(node, "an empty id-range item found");
1071 return;
1072 }
1073
1074 if (content=="start")
1075 {
1076 // "start" means [0], so store that in the set
1077 if (m_indices.count(0) == 0)
1078 {
1079 m_indices.insert(0);
1080 }
1081 else
1082 {
1083 wxXmlResource::Get()->ReportError
1084 (
1085 node,
1086 "duplicate id-range item found"
1087 );
1088 }
1089 }
1090 else if (content=="end")
1091 {
1092 // We can't yet be certain which XRCID this will be equivalent to, so
1093 // just note that there's an item with this name, in case we need to
1094 // inc the range size
1095 m_item_end_found = true;
1096 }
1097 else
1098 {
1099 // Anything else will be an integer, or rubbish
1100 unsigned long l;
1101 if ( content.ToULong(&l) )
1102 {
1103 if (m_indices.count(l) == 0)
1104 {
1105 m_indices.insert(l);
1106 // Check that this item wouldn't fall outside the current range
1107 // extent
1108 if (l >= m_size)
1109 {
1110 m_size = l + 1;
1111 }
1112 }
1113 else
1114 {
1115 wxXmlResource::Get()->ReportError
1116 (
1117 node,
1118 "duplicate id-range item found"
1119 );
1120 }
1121
1122 }
1123 else
1124 {
1125 wxXmlResource::Get()->ReportError
1126 (
1127 node,
1128 "an id-range item had a malformed index"
1129 );
1130 }
1131 }
1132}
1133
1134void wxIdRange::Finalise(const wxXmlNode* node)
1135{
1136 wxCHECK_RET( !IsFinalised(),
1137 "Trying to finalise an already-finalised range" );
1138
1139 // Now we know about all the items, we can get an accurate range size
1140 // Expand any requested range-size if there were more items than would fit
1141 m_size = wxMax(m_size, m_indices.size());
1142
1143 // If an item is explicitly called foo[end], ensure it won't clash with
1144 // another item
1145 if ( m_item_end_found && m_indices.count(m_size-1) )
1146 ++m_size;
1147 if (m_size == 0)
1148 {
1149 // This will happen if someone creates a range but no items in this xrc
1150 // file Report the error and abort, but don't finalise, in case items
1151 // appear later
1152 wxXmlResource::Get()->ReportError
1153 (
1154 node,
1155 "trying to create an empty id-range"
1156 );
1157 return;
1158 }
1159
1160 if (m_start==0)
1161 {
1162 // This is the usual case, where the user didn't specify a start ID
1163 // So get the range using NewControlId().
1164 //
1165 // NB: negative numbers, but NewControlId already returns the most
1166 // negative
1167 m_start = wxWindow::NewControlId(m_size);
1168 wxCHECK_RET( m_start != wxID_NONE,
1169 "insufficient IDs available to create range" );
1170 m_end = m_start + m_size - 1;
1171 }
1172 else
1173 {
1174 // The user already specified a start value, which must be positive
1175 m_end = m_start + m_size - 1;
1176 }
1177
1178 // Create the XRCIDs
1179 for (int i=m_start; i <= m_end; ++i)
1180 {
1181 // First clear any pre-existing XRCID
1182 // Necessary for wxXmlResource::Unload() followed by Load()
1183 wxIdRangeManager::RemoveXRCIDEntry(
1184 m_name + wxString::Format("[%i]", i-m_start));
1185
1186 // Use the second parameter of GetXRCID to force it to take the value i
1187 wxXmlResource::GetXRCID(m_name + wxString::Format("[%i]", i-m_start), i);
e7cad4b7
VZ
1188 wxLogTrace("xrcrange",
1189 "integer = %i %s now returns %i",
1190 i,
1191 m_name + wxString::Format("[%i]", i-m_start),
1192 XRCID((m_name + wxString::Format("[%i]", i-m_start)).mb_str()));
0526c8cc
VZ
1193 }
1194 // and these special ones
1195 wxIdRangeManager::RemoveXRCIDEntry(m_name + "[start]");
1196 wxXmlResource::GetXRCID(m_name + "[start]", m_start);
1197 wxIdRangeManager::RemoveXRCIDEntry(m_name + "[end]");
1198 wxXmlResource::GetXRCID(m_name + "[end]", m_end);
1199 wxLogTrace("xrcrange","%s[start] = %i %s[end] = %i",
1200 m_name.mb_str(),XRCID(wxString(m_name+"[start]").mb_str()),
1201 m_name.mb_str(),XRCID(wxString(m_name+"[end]").mb_str()));
1202
1203 m_finalised = true;
1204}
1205
1206wxIdRangeManager *wxIdRangeManager::ms_instance = NULL;
1207
1208/*static*/ wxIdRangeManager *wxIdRangeManager::Get()
1209{
1210 if ( !ms_instance )
1211 ms_instance = new wxIdRangeManager;
1212 return ms_instance;
1213}
1214
1215/*static*/ wxIdRangeManager *wxIdRangeManager::Set(wxIdRangeManager *res)
1216{
1217 wxIdRangeManager *old = ms_instance;
1218 ms_instance = res;
1219 return old;
1220}
1221
1222wxIdRangeManager::~wxIdRangeManager()
1223{
1224 for ( wxVector<wxIdRange*>::iterator i = m_IdRanges.begin();
1225 i != m_IdRanges.end(); ++i )
1226 {
1227 delete *i;
1228 }
1229 m_IdRanges.clear();
1230
1231 delete ms_instance;
1232}
1233
1234void wxIdRangeManager::AddRange(const wxXmlNode* node)
1235{
1236 wxString name = node->GetAttribute("name");
1237 wxString start = node->GetAttribute("start", "0");
1238 wxString size = node->GetAttribute("size", "0");
1239 if (name.empty())
1240 {
1241 wxXmlResource::Get()->ReportError
1242 (
1243 node,
1244 "xrc file contains an id-range without a name"
1245 );
1246 return;
1247 }
1248
1249 int index = Find(name);
1250 if (index == wxNOT_FOUND)
1251 {
1252 wxLogTrace("xrcrange",
1253 "Adding ID range, name=%s start=%s size=%s",
1254 name, start, size);
1255
1256 m_IdRanges.push_back(new wxIdRange(node, name, start, size));
1257 }
1258 else
1259 {
1260 // There was already a range with this name. Let's hope this is
1261 // from an Unload()/(re)Load(), not an unintentional duplication
1262 wxLogTrace("xrcrange",
1263 "Replacing ID range, name=%s start=%s size=%s",
1264 name, start, size);
1265
1266 wxIdRange* oldrange = m_IdRanges.at(index);
1267 m_IdRanges.at(index) = new wxIdRange(node, name, start, size);
1268 delete oldrange;
1269 }
1270}
1271
1272wxIdRange *
1273wxIdRangeManager::FindRangeForItem(const wxXmlNode* node,
1274 const wxString& item,
1275 wxString& value) const
1276{
1277 wxString basename = item.BeforeFirst('[');
1278 wxCHECK_MSG( !basename.empty(), NULL,
1279 "an id-range item without a range name" );
1280
1281 int index = Find(basename);
1282 if (index == wxNOT_FOUND)
1283 {
1284 // Don't assert just because we've found an unexpected foo[123]
1285 // Someone might just want such a name, nothing to do with ranges
1286 return NULL;
1287 }
1288
1289 value = item.Mid(basename.Len());
1290 if (value.at(value.length()-1)==']')
1291 {
1292 return m_IdRanges.at(index);
1293 }
1294 wxXmlResource::Get()->ReportError(node, "a malformed id-range item");
1295 return NULL;
1296}
1297
1298void
1299wxIdRangeManager::NotifyRangeOfItem(const wxXmlNode* node,
1300 const wxString& item) const
1301{
1302 wxString value;
1303 wxIdRange* range = FindRangeForItem(node, item, value);
1304 if (range)
1305 range->NoteItem(node, value);
1306}
1307
1308int wxIdRangeManager::Find(const wxString& rangename) const
1309{
1310 for ( int i=0; i < (int)m_IdRanges.size(); ++i )
1311 {
1312 if (m_IdRanges.at(i)->GetName() == rangename)
1313 return i;
1314 }
1315
1316 return wxNOT_FOUND;
1317}
1318
1319void wxIdRangeManager::FinaliseRanges(const wxXmlNode* node) const
1320{
1321 for ( wxVector<wxIdRange*>::const_iterator i = m_IdRanges.begin();
1322 i != m_IdRanges.end(); ++i )
1323 {
1324 // Check if this range has already been finalised. Quite possible,
1325 // as FinaliseRanges() gets called for each .xrc file loaded
1326 if (!(*i)->IsFinalised())
1327 {
1328 wxLogTrace("xrcrange", "Finalising ID range %s", (*i)->GetName());
1329 (*i)->Finalise(node);
1330 }
1331 }
1332}
1333
78d14f80 1334
eb2d0d23
VS
1335class wxXmlSubclassFactories : public wxVector<wxXmlSubclassFactory*>
1336{
1337 // this is a class so that it can be forward-declared
1338};
2b5f62a0 1339
eb2d0d23 1340wxXmlSubclassFactories *wxXmlResource::ms_subclassFactories = NULL;
2b5f62a0
VZ
1341
1342/*static*/ void wxXmlResource::AddSubclassFactory(wxXmlSubclassFactory *factory)
1343{
1344 if (!ms_subclassFactories)
1345 {
eb2d0d23 1346 ms_subclassFactories = new wxXmlSubclassFactories;
2b5f62a0 1347 }
eb2d0d23 1348 ms_subclassFactories->push_back(factory);
2b5f62a0
VZ
1349}
1350
1351class wxXmlSubclassFactoryCXX : public wxXmlSubclassFactory
1352{
1353public:
1354 ~wxXmlSubclassFactoryCXX() {}
1355
1356 wxObject *Create(const wxString& className)
1357 {
1358 wxClassInfo* classInfo = wxClassInfo::FindClass(className);
1359
1360 if (classInfo)
1361 return classInfo->CreateObject();
1362 else
1363 return NULL;
1364 }
1365};
1366
1367
1368
78d14f80 1369
78d14f80
VS
1370wxXmlResourceHandler::wxXmlResourceHandler()
1371 : m_node(NULL), m_parent(NULL), m_instance(NULL),
9a8d8c5a 1372 m_parentAsWindow(NULL)
78d14f80
VS
1373{}
1374
1375
1376
1377wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance)
1378{
1379 wxXmlNode *myNode = m_node;
1380 wxString myClass = m_class;
1381 wxObject *myParent = m_parent, *myInstance = m_instance;
9a8d8c5a 1382 wxWindow *myParentAW = m_parentAsWindow;
78d14f80 1383
daa85ee3 1384 m_instance = instance;
288b6107 1385 if (!m_instance && node->HasAttribute(wxT("subclass")) &&
daa85ee3
VS
1386 !(m_resource->GetFlags() & wxXRC_NO_SUBCLASSING))
1387 {
288b6107 1388 wxString subclass = node->GetAttribute(wxT("subclass"), wxEmptyString);
2b5f62a0 1389 if (!subclass.empty())
daa85ee3 1390 {
eb2d0d23
VS
1391 for (wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
1392 i != wxXmlResource::ms_subclassFactories->end(); ++i)
2b5f62a0 1393 {
eb2d0d23 1394 m_instance = (*i)->Create(subclass);
2b5f62a0
VZ
1395 if (m_instance)
1396 break;
1397 }
daa85ee3 1398
2b5f62a0
VZ
1399 if (!m_instance)
1400 {
288b6107 1401 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
819559b2
VS
1402 ReportError
1403 (
1404 node,
1405 wxString::Format
1406 (
1407 "subclass \"%s\" not found for resource \"%s\", not subclassing",
1408 subclass, name
1409 )
1410 );
2b5f62a0
VZ
1411 }
1412 }
daa85ee3
VS
1413 }
1414
78d14f80 1415 m_node = node;
288b6107 1416 m_class = node->GetAttribute(wxT("class"), wxEmptyString);
78d14f80 1417 m_parent = parent;
78d14f80 1418 m_parentAsWindow = wxDynamicCast(m_parent, wxWindow);
78d14f80
VS
1419
1420 wxObject *returned = DoCreateResource();
1421
1422 m_node = myNode;
1423 m_class = myClass;
1424 m_parent = myParent; m_parentAsWindow = myParentAW;
9a8d8c5a 1425 m_instance = myInstance;
78d14f80
VS
1426
1427 return returned;
1428}
1429
1430
1431void wxXmlResourceHandler::AddStyle(const wxString& name, int value)
1432{
1433 m_styleNames.Add(name);
1434 m_styleValues.Add(value);
1435}
1436
1437
1438
1439void wxXmlResourceHandler::AddWindowStyles()
1440{
9dc579b3 1441 XRC_ADD_STYLE(wxCLIP_CHILDREN);
d54a3e73
VZ
1442
1443 // the border styles all have the old and new names, recognize both for now
1444 XRC_ADD_STYLE(wxSIMPLE_BORDER); XRC_ADD_STYLE(wxBORDER_SIMPLE);
1445 XRC_ADD_STYLE(wxSUNKEN_BORDER); XRC_ADD_STYLE(wxBORDER_SUNKEN);
b37e592b
JS
1446 XRC_ADD_STYLE(wxDOUBLE_BORDER); XRC_ADD_STYLE(wxBORDER_DOUBLE); // deprecated
1447 XRC_ADD_STYLE(wxBORDER_THEME);
d54a3e73
VZ
1448 XRC_ADD_STYLE(wxRAISED_BORDER); XRC_ADD_STYLE(wxBORDER_RAISED);
1449 XRC_ADD_STYLE(wxSTATIC_BORDER); XRC_ADD_STYLE(wxBORDER_STATIC);
1450 XRC_ADD_STYLE(wxNO_BORDER); XRC_ADD_STYLE(wxBORDER_NONE);
1451
daa85ee3
VS
1452 XRC_ADD_STYLE(wxTRANSPARENT_WINDOW);
1453 XRC_ADD_STYLE(wxWANTS_CHARS);
43840d8b 1454 XRC_ADD_STYLE(wxTAB_TRAVERSAL);
daa85ee3 1455 XRC_ADD_STYLE(wxNO_FULL_REPAINT_ON_RESIZE);
7539ba56 1456 XRC_ADD_STYLE(wxFULL_REPAINT_ON_RESIZE);
162a4f93 1457 XRC_ADD_STYLE(wxALWAYS_SHOW_SB);
9f4ed861 1458 XRC_ADD_STYLE(wxWS_EX_BLOCK_EVENTS);
b0802e64 1459 XRC_ADD_STYLE(wxWS_EX_VALIDATE_RECURSIVELY);
78d14f80
VS
1460}
1461
1462
1463
1464bool wxXmlResourceHandler::HasParam(const wxString& param)
1465{
1466 return (GetParamNode(param) != NULL);
1467}
1468
1469
1470int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
1471{
1472 wxString s = GetParamValue(param);
1473
1474 if (!s) return defaults;
1475
2b5f62a0 1476 wxStringTokenizer tkn(s, wxT("| \t\n"), wxTOKEN_STRTOK);
78d14f80
VS
1477 int style = 0;
1478 int index;
1479 wxString fl;
1480 while (tkn.HasMoreTokens())
1481 {
1482 fl = tkn.GetNextToken();
1483 index = m_styleNames.Index(fl);
1484 if (index != wxNOT_FOUND)
819559b2 1485 {
78d14f80 1486 style |= m_styleValues[index];
819559b2 1487 }
78d14f80 1488 else
819559b2
VS
1489 {
1490 ReportParamError
1491 (
1492 param,
1493 wxString::Format("unknown style flag \"%s\"", fl)
1494 );
1495 }
78d14f80
VS
1496 }
1497 return style;
1498}
1499
1500
1501
ee1046d1 1502wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate)
78d14f80 1503{
7b56015f
VS
1504 wxXmlNode *parNode = GetParamNode(param);
1505 wxString str1(GetNodeContent(parNode));
78d14f80 1506 wxString str2;
424af7aa
VS
1507
1508 // "\\" wasn't translated to "\" prior to 2.5.3.0:
1509 const bool escapeBackslash = (m_resource->CompareVersion(2,5,3,0) >= 0);
78d14f80 1510
b272b6dc
RD
1511 // VS: First version of XRC resources used $ instead of & (which is
1512 // illegal in XML), but later I realized that '_' fits this purpose
718cf160 1513 // much better (because &File means "File with F underlined").
424af7aa
VS
1514 const wxChar amp_char = (m_resource->CompareVersion(2,3,0,1) < 0)
1515 ? '$' : '_';
78d14f80 1516
424af7aa 1517 for ( wxString::const_iterator dt = str1.begin(); dt != str1.end(); ++dt )
78d14f80
VS
1518 {
1519 // Remap amp_char to &, map double amp_char to amp_char (for things
1520 // like "&File..." -- this is illegal in XML, so we use "_File..."):
424af7aa 1521 if ( *dt == amp_char )
78d14f80
VS
1522 {
1523 if ( *(++dt) == amp_char )
1524 str2 << amp_char;
1525 else
1526 str2 << wxT('&') << *dt;
1527 }
984c33c9 1528 // Remap \n to CR, \r to LF, \t to TAB, \\ to \:
424af7aa
VS
1529 else if ( *dt == wxT('\\') )
1530 {
1531 switch ( (*(++dt)).GetValue() )
78d14f80 1532 {
984c33c9
VS
1533 case wxT('n'):
1534 str2 << wxT('\n');
1535 break;
e7a3a5a5 1536
984c33c9
VS
1537 case wxT('t'):
1538 str2 << wxT('\t');
1539 break;
e7a3a5a5 1540
984c33c9
VS
1541 case wxT('r'):
1542 str2 << wxT('\r');
1543 break;
1544
1545 case wxT('\\') :
1546 // "\\" wasn't translated to "\" prior to 2.5.3.0:
424af7aa 1547 if ( escapeBackslash )
984c33c9
VS
1548 {
1549 str2 << wxT('\\');
1550 break;
1551 }
1552 // else fall-through to default: branch below
e7a3a5a5 1553
984c33c9
VS
1554 default:
1555 str2 << wxT('\\') << *dt;
1556 break;
78d14f80 1557 }
424af7aa
VS
1558 }
1559 else
1560 {
1561 str2 << *dt;
1562 }
78d14f80 1563 }
b272b6dc 1564
7b56015f
VS
1565 if (m_resource->GetFlags() & wxXRC_USE_LOCALE)
1566 {
1567 if (translate && parNode &&
288b6107 1568 parNode->GetAttribute(wxT("translate"), wxEmptyString) != wxT("0"))
7b56015f 1569 {
d4a724d4 1570 return wxGetTranslation(str2, m_resource->GetDomain());
7b56015f
VS
1571 }
1572 else
1573 {
1574#if wxUSE_UNICODE
1575 return str2;
1576#else
1577 // The string is internally stored as UTF-8, we have to convert
1578 // it into system's default encoding so that it can be displayed:
6251e0ea 1579 return wxString(str2.wc_str(wxConvUTF8), wxConvLocal);
7b56015f
VS
1580#endif
1581 }
1582 }
8516a98b
DS
1583
1584 // If wxXRC_USE_LOCALE is not set, then the string is already in
1585 // system's default encoding in ANSI build, so we don't have to
1586 // do anything special here.
1587 return str2;
78d14f80
VS
1588}
1589
1590
1591
1592long wxXmlResourceHandler::GetLong(const wxString& param, long defaultv)
1593{
1594 long value;
1595 wxString str1 = GetParamValue(param);
1596
1597 if (!str1.ToLong(&value))
1598 value = defaultv;
1599
1600 return value;
1601}
e7a3a5a5 1602
1df61962
VS
1603float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv)
1604{
1d9473d3 1605 wxString str = GetParamValue(param);
1df61962 1606
9edb8fa0
VZ
1607 // strings in XRC always use C locale so make sure to use the
1608 // locale-independent wxString::ToCDouble() and not ToDouble() which uses
1609 // the current locale with a potentially different decimal point character
1d9473d3 1610 double value;
9edb8fa0 1611 if (!str.ToCDouble(&value))
1df61962
VS
1612 value = defaultv;
1613
17a1ebd1 1614 return wx_truncate_cast(float, value);
1df61962 1615}
78d14f80 1616
af1337b0 1617
78d14f80
VS
1618int wxXmlResourceHandler::GetID()
1619{
13de23f6 1620 return wxXmlResource::GetXRCID(GetName());
78d14f80
VS
1621}
1622
1623
af1337b0 1624
78d14f80
VS
1625wxString wxXmlResourceHandler::GetName()
1626{
288b6107 1627 return m_node->GetAttribute(wxT("name"), wxT("-1"));
78d14f80
VS
1628}
1629
1630
1631
8758875e
VZ
1632bool wxXmlResourceHandler::GetBoolAttr(const wxString& attr, bool defaultv)
1633{
1634 wxString v;
1635 return m_node->GetAttribute(attr, &v) ? v == '1' : defaultv;
1636}
1637
78d14f80
VS
1638bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv)
1639{
8758875e 1640 const wxString v = GetParamValue(param);
8516a98b 1641
8758875e 1642 return v.empty() ? defaultv : (v == '1');
78d14f80
VS
1643}
1644
1645
1df61962
VS
1646static wxColour GetSystemColour(const wxString& name)
1647{
1648 if (!name.empty())
1649 {
1650 #define SYSCLR(clr) \
9a83f860 1651 if (name == wxT(#clr)) return wxSystemSettings::GetColour(clr);
1df61962
VS
1652 SYSCLR(wxSYS_COLOUR_SCROLLBAR)
1653 SYSCLR(wxSYS_COLOUR_BACKGROUND)
1654 SYSCLR(wxSYS_COLOUR_DESKTOP)
1655 SYSCLR(wxSYS_COLOUR_ACTIVECAPTION)
1656 SYSCLR(wxSYS_COLOUR_INACTIVECAPTION)
1657 SYSCLR(wxSYS_COLOUR_MENU)
1658 SYSCLR(wxSYS_COLOUR_WINDOW)
1659 SYSCLR(wxSYS_COLOUR_WINDOWFRAME)
1660 SYSCLR(wxSYS_COLOUR_MENUTEXT)
1661 SYSCLR(wxSYS_COLOUR_WINDOWTEXT)
1662 SYSCLR(wxSYS_COLOUR_CAPTIONTEXT)
1663 SYSCLR(wxSYS_COLOUR_ACTIVEBORDER)
1664 SYSCLR(wxSYS_COLOUR_INACTIVEBORDER)
1665 SYSCLR(wxSYS_COLOUR_APPWORKSPACE)
1666 SYSCLR(wxSYS_COLOUR_HIGHLIGHT)
1667 SYSCLR(wxSYS_COLOUR_HIGHLIGHTTEXT)
1668 SYSCLR(wxSYS_COLOUR_BTNFACE)
1669 SYSCLR(wxSYS_COLOUR_3DFACE)
1670 SYSCLR(wxSYS_COLOUR_BTNSHADOW)
1671 SYSCLR(wxSYS_COLOUR_3DSHADOW)
1672 SYSCLR(wxSYS_COLOUR_GRAYTEXT)
1673 SYSCLR(wxSYS_COLOUR_BTNTEXT)
1674 SYSCLR(wxSYS_COLOUR_INACTIVECAPTIONTEXT)
1675 SYSCLR(wxSYS_COLOUR_BTNHIGHLIGHT)
1676 SYSCLR(wxSYS_COLOUR_BTNHILIGHT)
1677 SYSCLR(wxSYS_COLOUR_3DHIGHLIGHT)
1678 SYSCLR(wxSYS_COLOUR_3DHILIGHT)
1679 SYSCLR(wxSYS_COLOUR_3DDKSHADOW)
1680 SYSCLR(wxSYS_COLOUR_3DLIGHT)
1681 SYSCLR(wxSYS_COLOUR_INFOTEXT)
1682 SYSCLR(wxSYS_COLOUR_INFOBK)
1683 SYSCLR(wxSYS_COLOUR_LISTBOX)
1684 SYSCLR(wxSYS_COLOUR_HOTLIGHT)
1685 SYSCLR(wxSYS_COLOUR_GRADIENTACTIVECAPTION)
1686 SYSCLR(wxSYS_COLOUR_GRADIENTINACTIVECAPTION)
1687 SYSCLR(wxSYS_COLOUR_MENUHILIGHT)
1688 SYSCLR(wxSYS_COLOUR_MENUBAR)
1689 #undef SYSCLR
1690 }
1691
1692 return wxNullColour;
1693}
78d14f80 1694
984f1d84 1695wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& defaultv)
78d14f80
VS
1696{
1697 wxString v = GetParamValue(param);
984f1d84
VS
1698
1699 if ( v.empty() )
1700 return defaultv;
1701
68b4e4cf 1702 wxColour clr;
1df61962 1703
68b4e4cf
WS
1704 // wxString -> wxColour conversion
1705 if (!clr.Set(v))
78d14f80 1706 {
1df61962
VS
1707 // the colour doesn't use #RRGGBB format, check if it is symbolic
1708 // colour name:
68b4e4cf 1709 clr = GetSystemColour(v);
1df61962
VS
1710 if (clr.Ok())
1711 return clr;
e7a3a5a5 1712
819559b2
VS
1713 ReportParamError
1714 (
1715 param,
1716 wxString::Format("incorrect colour specification \"%s\"", v)
1717 );
78d14f80
VS
1718 return wxNullColour;
1719 }
1720
68b4e4cf 1721 return clr;
78d14f80
VS
1722}
1723
1c60f644
VS
1724namespace
1725{
1726
1727// if 'param' has stock_id/stock_client, extracts them and returns true
1728bool GetStockArtAttrs(const wxXmlNode *paramNode,
1729 const wxString& defaultArtClient,
1730 wxString& art_id, wxString& art_client)
1731{
1732 if ( paramNode )
1733 {
1734 art_id = paramNode->GetAttribute("stock_id", "");
1735
1736 if ( !art_id.empty() )
1737 {
1738 art_id = wxART_MAKE_ART_ID_FROM_STR(art_id);
1739
1740 art_client = paramNode->GetAttribute("stock_client", "");
1741 if ( art_client.empty() )
1742 art_client = defaultArtClient;
1743 else
1744 art_client = wxART_MAKE_CLIENT_ID_FROM_STR(art_client);
78d14f80 1745
1c60f644
VS
1746 return true;
1747 }
1748 }
1749
1750 return false;
1751}
1752
1753} // anonymous namespace
78d14f80 1754
92e898b0 1755wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
db59a97c
VS
1756 const wxArtClient& defaultArtClient,
1757 wxSize size)
326462ae 1758{
9c1d2aa2
VZ
1759 // it used to be possible to pass an empty string here to indicate that the
1760 // bitmap name should be read from this node itself but this is not
1761 // supported any more because GetBitmap(m_node) can be used directly
1762 // instead
1763 wxASSERT_MSG( !param.empty(), "bitmap parameter name can't be empty" );
1764
1765 const wxXmlNode* const node = GetParamNode(param);
1766
1767 if ( !node )
1768 {
1769 // this is not an error as bitmap parameter could be optional
1770 return wxNullBitmap;
1771 }
1772
1773 return GetBitmap(node, defaultArtClient, size);
326462ae
VZ
1774}
1775
1776wxBitmap wxXmlResourceHandler::GetBitmap(const wxXmlNode* node,
1777 const wxArtClient& defaultArtClient,
1778 wxSize size)
78d14f80 1779{
9c1d2aa2
VZ
1780 wxCHECK_MSG( node, wxNullBitmap, "bitmap node can't be NULL" );
1781
db59a97c 1782 /* If the bitmap is specified as stock item, query wxArtProvider for it: */
1c60f644 1783 wxString art_id, art_client;
326462ae 1784 if ( GetStockArtAttrs(node, defaultArtClient,
1c60f644 1785 art_id, art_client) )
af1337b0 1786 {
1c60f644
VS
1787 wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size));
1788 if ( stockArt.Ok() )
1789 return stockArt;
af1337b0
JS
1790 }
1791
92e898b0 1792 /* ...or load the bitmap from file: */
326462ae 1793 wxString name = GetParamValue(node);
e7a3a5a5 1794 if (name.empty()) return wxNullBitmap;
78d14f80 1795#if wxUSE_FILESYSTEM
4532786e 1796 wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
78d14f80
VS
1797 if (fsfile == NULL)
1798 {
819559b2
VS
1799 ReportParamError
1800 (
326462ae 1801 node->GetName(),
819559b2
VS
1802 wxString::Format("cannot open bitmap resource \"%s\"", name)
1803 );
78d14f80
VS
1804 return wxNullBitmap;
1805 }
1806 wxImage img(*(fsfile->GetStream()));
1807 delete fsfile;
1808#else
45f3249b 1809 wxImage img(name);
78d14f80 1810#endif
af1337b0 1811
78d14f80
VS
1812 if (!img.Ok())
1813 {
819559b2
VS
1814 ReportParamError
1815 (
326462ae 1816 node->GetName(),
819559b2
VS
1817 wxString::Format("cannot create bitmap from \"%s\"", name)
1818 );
78d14f80
VS
1819 return wxNullBitmap;
1820 }
1821 if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
b272b6dc 1822 return wxBitmap(img);
78d14f80
VS
1823}
1824
78d14f80 1825
92e898b0 1826wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
db59a97c
VS
1827 const wxArtClient& defaultArtClient,
1828 wxSize size)
326462ae 1829{
9c1d2aa2
VZ
1830 // see comment in GetBitmap(wxString) overload
1831 wxASSERT_MSG( !param.empty(), "icon parameter name can't be empty" );
1832
1833 const wxXmlNode* const node = GetParamNode(param);
1834
1835 if ( !node )
1836 {
1837 // this is not an error as icon parameter could be optional
1838 return wxIcon();
1839 }
1840
1841 return GetIcon(node, defaultArtClient, size);
326462ae
VZ
1842}
1843
1844wxIcon wxXmlResourceHandler::GetIcon(const wxXmlNode* node,
1845 const wxArtClient& defaultArtClient,
1846 wxSize size)
78d14f80 1847{
78d14f80 1848 wxIcon icon;
326462ae 1849 icon.CopyFromBitmap(GetBitmap(node, defaultArtClient, size));
78d14f80
VS
1850 return icon;
1851}
1852
326462ae 1853
1c60f644
VS
1854wxIconBundle wxXmlResourceHandler::GetIconBundle(const wxString& param,
1855 const wxArtClient& defaultArtClient)
1856{
1857 wxString art_id, art_client;
1858 if ( GetStockArtAttrs(GetParamNode(param), defaultArtClient,
1859 art_id, art_client) )
1860 {
1861 wxIconBundle stockArt(wxArtProvider::GetIconBundle(art_id, art_client));
1862 if ( stockArt.IsOk() )
1863 return stockArt;
1864 }
1865
1866 const wxString name = GetParamValue(param);
1867 if ( name.empty() )
1868 return wxNullIconBundle;
1869
1870#if wxUSE_FILESYSTEM
1871 wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
1872 if ( fsfile == NULL )
1873 {
1874 ReportParamError
1875 (
1876 param,
1877 wxString::Format("cannot open icon resource \"%s\"", name)
1878 );
1879 return wxNullIconBundle;
1880 }
1881
1882 wxIconBundle bundle(*(fsfile->GetStream()));
1883 delete fsfile;
1884#else
1885 wxIconBundle bundle(name);
1886#endif
1887
1888 if ( !bundle.IsOk() )
1889 {
1890 ReportParamError
1891 (
1892 param,
1893 wxString::Format("cannot create icon from \"%s\"", name)
1894 );
1895 return wxNullIconBundle;
1896 }
1897
1898 return bundle;
1899}
78d14f80
VS
1900
1901
326462ae
VZ
1902wxImageList *wxXmlResourceHandler::GetImageList(const wxString& param)
1903{
1904 wxXmlNode * const imagelist_node = GetParamNode(param);
1905 if ( !imagelist_node )
1906 return NULL;
1907
1908 wxXmlNode * const oldnode = m_node;
1909 m_node = imagelist_node;
1910
fe97acf0
VZ
1911 // Get the size if we have it, otherwise we will use the size of the first
1912 // list element.
326462ae 1913 wxSize size = GetSize();
326462ae 1914
fe97acf0
VZ
1915 // Start adding images, we'll create the image list when adding the first
1916 // one.
1917 wxImageList * imagelist = NULL;
326462ae
VZ
1918 wxString parambitmap = wxT("bitmap");
1919 if ( HasParam(parambitmap) )
1920 {
1921 wxXmlNode *n = m_node->GetChildren();
1922 while (n)
1923 {
1924 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == parambitmap)
1925 {
fe97acf0
VZ
1926 wxIcon icon = GetIcon(n);
1927 if ( !imagelist )
1928 {
1929 // We need the real image list size to create it.
1930 if ( size == wxDefaultSize )
1931 size = icon.GetSize();
1932
1933 // We use the mask by default.
1934 bool mask = !HasParam(wxS("mask")) || GetBool(wxS("mask"));
1935
1936 imagelist = new wxImageList(size.x, size.y, mask);
1937 }
1938
326462ae 1939 // add icon instead of bitmap to keep the bitmap mask
fe97acf0 1940 imagelist->Add(icon);
326462ae
VZ
1941 }
1942 n = n->GetNext();
1943 }
1944 }
1945
1946 m_node = oldnode;
1947 return imagelist;
1948}
1949
78d14f80
VS
1950wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
1951{
2b5f62a0
VZ
1952 wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!"));
1953
78d14f80
VS
1954 wxXmlNode *n = m_node->GetChildren();
1955
1956 while (n)
1957 {
1958 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
cffff062
VZ
1959 {
1960 // TODO: check that there are no other properties/parameters with
1961 // the same name and log an error if there are (can't do this
1962 // right now as I'm not sure if it's not going to break code
1963 // using this function in unintentional way (i.e. for
1964 // accessing other things than properties), for example
1965 // wxBitmapComboBoxXmlHandler almost surely does
78d14f80 1966 return n;
cffff062 1967 }
78d14f80
VS
1968 n = n->GetNext();
1969 }
1970 return NULL;
1971}
1972
8ec22772 1973/* static */
2d672c46
MW
1974bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
1975{
8ec22772 1976 return node->GetAttribute(wxT("class")) == classname;
2d672c46
MW
1977}
1978
1979
1980
326462ae 1981wxString wxXmlResourceHandler::GetNodeContent(const wxXmlNode *node)
78d14f80 1982{
326462ae 1983 const wxXmlNode *n = node;
78d14f80
VS
1984 if (n == NULL) return wxEmptyString;
1985 n = n->GetChildren();
1986
1987 while (n)
1988 {
1989 if (n->GetType() == wxXML_TEXT_NODE ||
1990 n->GetType() == wxXML_CDATA_SECTION_NODE)
1991 return n->GetContent();
1992 n = n->GetNext();
1993 }
1994 return wxEmptyString;
1995}
1996
1997
1998
1999wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
2000{
e7a3a5a5 2001 if (param.empty())
78d14f80
VS
2002 return GetNodeContent(m_node);
2003 else
2004 return GetNodeContent(GetParamNode(param));
2005}
2006
326462ae
VZ
2007wxString wxXmlResourceHandler::GetParamValue(const wxXmlNode* node)
2008{
2009 return GetNodeContent(node);
2010}
78d14f80
VS
2011
2012
0c00c86f
VS
2013wxSize wxXmlResourceHandler::GetSize(const wxString& param,
2014 wxWindow *windowToUse)
78d14f80
VS
2015{
2016 wxString s = GetParamValue(param);
e7a3a5a5 2017 if (s.empty()) s = wxT("-1,-1");
78d14f80 2018 bool is_dlg;
d1f47235 2019 long sx, sy = 0;
78d14f80 2020
88a7a4e1 2021 is_dlg = s[s.length()-1] == wxT('d');
78d14f80
VS
2022 if (is_dlg) s.RemoveLast();
2023
2024 if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
2025 !s.AfterLast(wxT(',')).ToLong(&sy))
2026 {
819559b2
VS
2027 ReportParamError
2028 (
2029 param,
2030 wxString::Format("cannot parse coordinates value \"%s\"", s)
2031 );
78d14f80
VS
2032 return wxDefaultSize;
2033 }
2034
2035 if (is_dlg)
2036 {
0c00c86f
VS
2037 if (windowToUse)
2038 {
2039 return wxDLG_UNIT(windowToUse, wxSize(sx, sy));
2040 }
2041 else if (m_parentAsWindow)
2042 {
78d14f80 2043 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, sy));
0c00c86f 2044 }
78d14f80
VS
2045 else
2046 {
819559b2
VS
2047 ReportParamError
2048 (
2049 param,
2050 "cannot convert dialog units: dialog unknown"
2051 );
78d14f80
VS
2052 return wxDefaultSize;
2053 }
2054 }
8516a98b
DS
2055
2056 return wxSize(sx, sy);
78d14f80
VS
2057}
2058
2059
2060
2061wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
2062{
2063 wxSize sz = GetSize(param);
2064 return wxPoint(sz.x, sz.y);
2065}
2066
2067
2068
0c00c86f
VS
2069wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
2070 wxCoord defaultv,
2071 wxWindow *windowToUse)
78d14f80
VS
2072{
2073 wxString s = GetParamValue(param);
e7a3a5a5 2074 if (s.empty()) return defaultv;
78d14f80
VS
2075 bool is_dlg;
2076 long sx;
2077
88a7a4e1 2078 is_dlg = s[s.length()-1] == wxT('d');
78d14f80
VS
2079 if (is_dlg) s.RemoveLast();
2080
2081 if (!s.ToLong(&sx))
2082 {
819559b2
VS
2083 ReportParamError
2084 (
2085 param,
2086 wxString::Format("cannot parse dimension value \"%s\"", s)
2087 );
78d14f80
VS
2088 return defaultv;
2089 }
2090
2091 if (is_dlg)
2092 {
0c00c86f
VS
2093 if (windowToUse)
2094 {
2095 return wxDLG_UNIT(windowToUse, wxSize(sx, 0)).x;
2096 }
2097 else if (m_parentAsWindow)
2098 {
78d14f80 2099 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, 0)).x;
0c00c86f 2100 }
78d14f80
VS
2101 else
2102 {
819559b2
VS
2103 ReportParamError
2104 (
2105 param,
2106 "cannot convert dialog units: dialog unknown"
2107 );
78d14f80
VS
2108 return defaultv;
2109 }
2110 }
8516a98b
DS
2111
2112 return sx;
78d14f80
VS
2113}
2114
2115
1df61962
VS
2116// Get system font index using indexname
2117static wxFont GetSystemFont(const wxString& name)
2118{
2119 if (!name.empty())
2120 {
2121 #define SYSFNT(fnt) \
9a83f860 2122 if (name == wxT(#fnt)) return wxSystemSettings::GetFont(fnt);
1df61962
VS
2123 SYSFNT(wxSYS_OEM_FIXED_FONT)
2124 SYSFNT(wxSYS_ANSI_FIXED_FONT)
2125 SYSFNT(wxSYS_ANSI_VAR_FONT)
2126 SYSFNT(wxSYS_SYSTEM_FONT)
2127 SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
1df61962
VS
2128 SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
2129 SYSFNT(wxSYS_DEFAULT_GUI_FONT)
2130 #undef SYSFNT
2131 }
2132
2133 return wxNullFont;
2134}
78d14f80
VS
2135
2136wxFont wxXmlResourceHandler::GetFont(const wxString& param)
2137{
2138 wxXmlNode *font_node = GetParamNode(param);
2139 if (font_node == NULL)
2140 {
819559b2
VS
2141 ReportError(
2142 wxString::Format("cannot find font node \"%s\"", param));
78d14f80
VS
2143 return wxNullFont;
2144 }
2145
2146 wxXmlNode *oldnode = m_node;
2147 m_node = font_node;
2148
1df61962 2149 // font attributes:
78d14f80 2150
1df61962 2151 // size
94245f6d 2152 int isize = -1;
1df61962 2153 bool hasSize = HasParam(wxT("size"));
e7a3a5a5 2154 if (hasSize)
94245f6d 2155 isize = GetLong(wxT("size"), -1);
78d14f80 2156
1df61962
VS
2157 // style
2158 int istyle = wxNORMAL;
2159 bool hasStyle = HasParam(wxT("style"));
2160 if (hasStyle)
2161 {
2162 wxString style = GetParamValue(wxT("style"));
e7a3a5a5 2163 if (style == wxT("italic"))
1df61962 2164 istyle = wxITALIC;
e7a3a5a5 2165 else if (style == wxT("slant"))
1df61962
VS
2166 istyle = wxSLANT;
2167 }
78d14f80 2168
1df61962
VS
2169 // weight
2170 int iweight = wxNORMAL;
2171 bool hasWeight = HasParam(wxT("weight"));
2172 if (hasWeight)
2173 {
2174 wxString weight = GetParamValue(wxT("weight"));
e7a3a5a5 2175 if (weight == wxT("bold"))
1df61962 2176 iweight = wxBOLD;
e7a3a5a5 2177 else if (weight == wxT("light"))
1df61962
VS
2178 iweight = wxLIGHT;
2179 }
e7a3a5a5 2180
1df61962
VS
2181 // underline
2182 bool hasUnderlined = HasParam(wxT("underlined"));
2183 bool underlined = hasUnderlined ? GetBool(wxT("underlined"), false) : false;
78d14f80 2184
1df61962
VS
2185 // family and facename
2186 int ifamily = wxDEFAULT;
2187 bool hasFamily = HasParam(wxT("family"));
2188 if (hasFamily)
78d14f80 2189 {
1df61962
VS
2190 wxString family = GetParamValue(wxT("family"));
2191 if (family == wxT("decorative")) ifamily = wxDECORATIVE;
2192 else if (family == wxT("roman")) ifamily = wxROMAN;
2193 else if (family == wxT("script")) ifamily = wxSCRIPT;
2194 else if (family == wxT("swiss")) ifamily = wxSWISS;
2195 else if (family == wxT("modern")) ifamily = wxMODERN;
2196 else if (family == wxT("teletype")) ifamily = wxTELETYPE;
2197 }
e7a3a5a5
WS
2198
2199
1df61962
VS
2200 wxString facename;
2201 bool hasFacename = HasParam(wxT("face"));
2202 if (hasFacename)
2203 {
2204 wxString faces = GetParamValue(wxT("face"));
1df61962 2205 wxStringTokenizer tk(faces, wxT(","));
63feebce
VS
2206#if wxUSE_FONTENUM
2207 wxArrayString facenames(wxFontEnumerator::GetFacenames());
1df61962 2208 while (tk.HasMoreTokens())
78d14f80 2209 {
6540132f 2210 int index = facenames.Index(tk.GetNextToken(), false);
1df61962
VS
2211 if (index != wxNOT_FOUND)
2212 {
6540132f 2213 facename = facenames[index];
1df61962
VS
2214 break;
2215 }
78d14f80 2216 }
63feebce
VS
2217#else // !wxUSE_FONTENUM
2218 // just use the first face name if we can't check its availability:
2219 if (tk.HasMoreTokens())
2220 facename = tk.GetNextToken();
2221#endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
78d14f80
VS
2222 }
2223
1df61962
VS
2224 // encoding
2225 wxFontEncoding enc = wxFONTENCODING_DEFAULT;
2226 bool hasEncoding = HasParam(wxT("encoding"));
dc2575ba 2227#if wxUSE_FONTMAP
1df61962
VS
2228 if (hasEncoding)
2229 {
2230 wxString encoding = GetParamValue(wxT("encoding"));
2231 wxFontMapper mapper;
e7a3a5a5 2232 if (!encoding.empty())
1df61962
VS
2233 enc = mapper.CharsetToEncoding(encoding);
2234 if (enc == wxFONTENCODING_SYSTEM)
2235 enc = wxFONTENCODING_DEFAULT;
2236 }
dc2575ba 2237#endif // wxUSE_FONTMAP
78d14f80 2238
1df61962 2239 // is this font based on a system font?
94245f6d 2240 wxFont font = GetSystemFont(GetParamValue(wxT("sysfont")));
e7a3a5a5 2241
94245f6d 2242 if (font.Ok())
1df61962 2243 {
94245f6d
VZ
2244 if (hasSize && isize != -1)
2245 font.SetPointSize(isize);
1df61962 2246 else if (HasParam(wxT("relativesize")))
94245f6d 2247 font.SetPointSize(int(font.GetPointSize() *
1df61962 2248 GetFloat(wxT("relativesize"))));
e7a3a5a5 2249
1df61962 2250 if (hasStyle)
94245f6d 2251 font.SetStyle(istyle);
1df61962 2252 if (hasWeight)
94245f6d 2253 font.SetWeight(iweight);
1df61962 2254 if (hasUnderlined)
94245f6d 2255 font.SetUnderlined(underlined);
1df61962 2256 if (hasFamily)
94245f6d 2257 font.SetFamily(ifamily);
1df61962 2258 if (hasFacename)
94245f6d 2259 font.SetFaceName(facename);
1df61962 2260 if (hasEncoding)
94245f6d
VZ
2261 font.SetDefaultEncoding(enc);
2262 }
2263 else // not based on system font
2264 {
2265 font = wxFont(isize == -1 ? wxNORMAL_FONT->GetPointSize() : isize,
2266 ifamily, istyle, iweight,
2267 underlined, facename, enc);
1df61962 2268 }
8516a98b
DS
2269
2270 m_node = oldnode;
94245f6d 2271 return font;
78d14f80
VS
2272}
2273
2274
2275void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
2276{
2277 //FIXME : add cursor
2278
2279 if (HasParam(wxT("exstyle")))
0099f343
JS
2280 // Have to OR it with existing style, since
2281 // some implementations (e.g. wxGTK) use the extra style
2282 // during creation
2283 wnd->SetExtraStyle(wnd->GetExtraStyle() | GetStyle(wxT("exstyle")));
78d14f80
VS
2284 if (HasParam(wxT("bg")))
2285 wnd->SetBackgroundColour(GetColour(wxT("bg")));
a7435c3e
VZ
2286 if (HasParam(wxT("ownbg")))
2287 wnd->SetOwnBackgroundColour(GetColour(wxT("ownbg")));
78d14f80
VS
2288 if (HasParam(wxT("fg")))
2289 wnd->SetForegroundColour(GetColour(wxT("fg")));
a7435c3e
VZ
2290 if (HasParam(wxT("ownfg")))
2291 wnd->SetOwnForegroundColour(GetColour(wxT("ownfg")));
78d14f80 2292 if (GetBool(wxT("enabled"), 1) == 0)
f80ea77b 2293 wnd->Enable(false);
78d14f80
VS
2294 if (GetBool(wxT("focused"), 0) == 1)
2295 wnd->SetFocus();
2296 if (GetBool(wxT("hidden"), 0) == 1)
f80ea77b 2297 wnd->Show(false);
78d14f80
VS
2298#if wxUSE_TOOLTIPS
2299 if (HasParam(wxT("tooltip")))
2300 wnd->SetToolTip(GetText(wxT("tooltip")));
2301#endif
2302 if (HasParam(wxT("font")))
a7435c3e
VZ
2303 wnd->SetFont(GetFont(wxT("font")));
2304 if (HasParam(wxT("ownfont")))
2305 wnd->SetOwnFont(GetFont(wxT("ownfont")));
b23030d6
JS
2306 if (HasParam(wxT("help")))
2307 wnd->SetHelpText(GetText(wxT("help")));
78d14f80
VS
2308}
2309
2310
2311void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
2312{
23239d94 2313 for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() )
78d14f80 2314 {
23239d94 2315 if ( IsObjectNode(n) )
78d14f80 2316 {
af0ac990
VZ
2317 m_resource->DoCreateResFromNode(*n, parent, NULL,
2318 this_hnd_only ? this : NULL);
78d14f80 2319 }
78d14f80
VS
2320 }
2321}
2322
2323
2324void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode)
2325{
2326 wxXmlNode *root;
2327 if (rootnode == NULL) root = m_node; else root = rootnode;
2328 wxXmlNode *n = root->GetChildren();
2329
2330 while (n)
2331 {
2332 if (n->GetType() == wxXML_ELEMENT_NODE && CanHandle(n))
2333 {
2334 CreateResource(n, parent, NULL);
2335 }
2336 n = n->GetNext();
2337 }
2338}
2339
2340
819559b2
VS
2341//-----------------------------------------------------------------------------
2342// errors reporting
2343//-----------------------------------------------------------------------------
2344
2345void wxXmlResourceHandler::ReportError(const wxString& message)
2346{
2347 m_resource->ReportError(m_node, message);
2348}
2349
2350void wxXmlResourceHandler::ReportError(wxXmlNode *context,
2351 const wxString& message)
2352{
2353 m_resource->ReportError(context ? context : m_node, message);
2354}
2355
2356void wxXmlResourceHandler::ReportParamError(const wxString& param,
2357 const wxString& message)
2358{
2359 m_resource->ReportError(GetParamNode(param), message);
2360}
2361
1f6ea935 2362void wxXmlResource::ReportError(const wxXmlNode *context, const wxString& message)
819559b2
VS
2363{
2364 if ( !context )
2365 {
2366 DoReportError("", NULL, message);
2367 return;
2368 }
78d14f80 2369
819559b2
VS
2370 // We need to find out the file that 'context' is part of. Performance of
2371 // this code is not critical, so we simply find the root XML node and
2372 // compare it with all loaded XRC files.
2373 const wxString filename = GetFileNameFromNode(context, Data());
78d14f80 2374
819559b2
VS
2375 DoReportError(filename, context, message);
2376}
78d14f80 2377
1f6ea935 2378void wxXmlResource::DoReportError(const wxString& xrcFile, const wxXmlNode *position,
819559b2
VS
2379 const wxString& message)
2380{
2381 const int line = position ? position->GetLineNumber() : -1;
2382
2383 wxString loc;
2384 if ( !xrcFile.empty() )
2385 loc = xrcFile + ':';
2386 if ( line != -1 )
2387 loc += wxString::Format("%d:", line);
2388 if ( !loc.empty() )
2389 loc += ' ';
2390
2391 wxLogError("XRC error: %s%s", loc, message);
2392}
78d14f80
VS
2393
2394
819559b2
VS
2395//-----------------------------------------------------------------------------
2396// XRCID implementation
2397//-----------------------------------------------------------------------------
78d14f80 2398
5ed345b7 2399#define XRCID_TABLE_SIZE 1024
78d14f80
VS
2400
2401
5ed345b7 2402struct XRCID_record
78d14f80 2403{
cf2810aa
VZ
2404 /* Hold the id so that once an id is allocated for a name, it
2405 does not get created again by NewControlId at least
2406 until we are done with it */
2407 wxWindowIDRef id;
c560da98 2408 char *key;
5ed345b7 2409 XRCID_record *next;
78d14f80
VS
2410};
2411
5ed345b7 2412static XRCID_record *XRCID_Records[XRCID_TABLE_SIZE] = {NULL};
78d14f80 2413
d807030e
VZ
2414// Extremely simplistic hash function which probably ought to be replaced with
2415// wxStringHash::stringHash().
2416static inline unsigned XRCIdHash(const char *str_id)
78d14f80 2417{
d807030e 2418 unsigned index = 0;
78d14f80 2419
e03951b7 2420 for (const char *c = str_id; *c != '\0'; c++) index += (unsigned int)*c;
5ed345b7 2421 index %= XRCID_TABLE_SIZE;
78d14f80 2422
d807030e
VZ
2423 return index;
2424}
2425
2426static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE)
2427{
2428 const unsigned index = XRCIdHash(str_id);
2429
2430
5ed345b7 2431 XRCID_record *oldrec = NULL;
5ed345b7 2432 for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
78d14f80 2433 {
00393283 2434 if (wxStrcmp(rec->key, str_id) == 0)
78d14f80
VS
2435 {
2436 return rec->id;
2437 }
78d14f80
VS
2438 oldrec = rec;
2439 }
2440
5ed345b7
VS
2441 XRCID_record **rec_var = (oldrec == NULL) ?
2442 &XRCID_Records[index] : &oldrec->next;
2443 *rec_var = new XRCID_record;
00393283 2444 (*rec_var)->key = wxStrdup(str_id);
78d14f80
VS
2445 (*rec_var)->next = NULL;
2446
c560da98 2447 char *end;
9b2a7469 2448 if (value_if_not_found != wxID_NONE)
13de23f6 2449 (*rec_var)->id = value_if_not_found;
85452d74
VS
2450 else
2451 {
13de23f6
VS
2452 int asint = wxStrtol(str_id, &end, 10);
2453 if (*str_id && *end == 0)
2454 {
2455 // if str_id was integer, keep it verbosely:
2456 (*rec_var)->id = asint;
2457 }
2458 else
2459 {
f35fdf7e 2460 (*rec_var)->id = wxWindowBase::NewControlId();
13de23f6 2461 }
85452d74
VS
2462 }
2463
78d14f80
VS
2464 return (*rec_var)->id;
2465}
2466
a58804ea 2467namespace
78d14f80 2468{
f35fdf7e 2469
a58804ea
VZ
2470// flag indicating whether standard XRC ids were already initialized
2471static bool gs_stdIDsAdded = false;
78d14f80 2472
a58804ea 2473void AddStdXRCID_Records()
13de23f6 2474{
c560da98 2475#define stdID(id) XRCID_Lookup(#id, id)
13de23f6 2476 stdID(-1);
c369d4f1
VS
2477
2478 stdID(wxID_ANY);
2479 stdID(wxID_SEPARATOR);
e7a3a5a5 2480
c369d4f1
VS
2481 stdID(wxID_OPEN);
2482 stdID(wxID_CLOSE);
2483 stdID(wxID_NEW);
2484 stdID(wxID_SAVE);
2485 stdID(wxID_SAVEAS);
2486 stdID(wxID_REVERT);
2487 stdID(wxID_EXIT);
2488 stdID(wxID_UNDO);
2489 stdID(wxID_REDO);
2490 stdID(wxID_HELP);
2491 stdID(wxID_PRINT);
2492 stdID(wxID_PRINT_SETUP);
e63f19ba 2493 stdID(wxID_PAGE_SETUP);
c369d4f1
VS
2494 stdID(wxID_PREVIEW);
2495 stdID(wxID_ABOUT);
2496 stdID(wxID_HELP_CONTENTS);
2497 stdID(wxID_HELP_COMMANDS);
2498 stdID(wxID_HELP_PROCEDURES);
2499 stdID(wxID_HELP_CONTEXT);
13de23f6 2500 stdID(wxID_CLOSE_ALL);
c369d4f1 2501 stdID(wxID_PREFERENCES);
d73195fd 2502 stdID(wxID_EDIT);
c369d4f1
VS
2503 stdID(wxID_CUT);
2504 stdID(wxID_COPY);
2505 stdID(wxID_PASTE);
2506 stdID(wxID_CLEAR);
2507 stdID(wxID_FIND);
2508 stdID(wxID_DUPLICATE);
2509 stdID(wxID_SELECTALL);
2510 stdID(wxID_DELETE);
2511 stdID(wxID_REPLACE);
2512 stdID(wxID_REPLACE_ALL);
2513 stdID(wxID_PROPERTIES);
2514 stdID(wxID_VIEW_DETAILS);
2515 stdID(wxID_VIEW_LARGEICONS);
2516 stdID(wxID_VIEW_SMALLICONS);
2517 stdID(wxID_VIEW_LIST);
2518 stdID(wxID_VIEW_SORTDATE);
2519 stdID(wxID_VIEW_SORTNAME);
2520 stdID(wxID_VIEW_SORTSIZE);
2521 stdID(wxID_VIEW_SORTTYPE);
2522 stdID(wxID_FILE1);
2523 stdID(wxID_FILE2);
2524 stdID(wxID_FILE3);
2525 stdID(wxID_FILE4);
2526 stdID(wxID_FILE5);
2527 stdID(wxID_FILE6);
2528 stdID(wxID_FILE7);
2529 stdID(wxID_FILE8);
2530 stdID(wxID_FILE9);
2531 stdID(wxID_OK);
2532 stdID(wxID_CANCEL);
2533 stdID(wxID_APPLY);
2534 stdID(wxID_YES);
2535 stdID(wxID_NO);
2536 stdID(wxID_STATIC);
2537 stdID(wxID_FORWARD);
2538 stdID(wxID_BACKWARD);
2539 stdID(wxID_DEFAULT);
2540 stdID(wxID_MORE);
2541 stdID(wxID_SETUP);
2542 stdID(wxID_RESET);
2543 stdID(wxID_CONTEXT_HELP);
2544 stdID(wxID_YESTOALL);
2545 stdID(wxID_NOTOALL);
2546 stdID(wxID_ABORT);
2547 stdID(wxID_RETRY);
2548 stdID(wxID_IGNORE);
2549 stdID(wxID_ADD);
2550 stdID(wxID_REMOVE);
2551 stdID(wxID_UP);
2552 stdID(wxID_DOWN);
2553 stdID(wxID_HOME);
2554 stdID(wxID_REFRESH);
2555 stdID(wxID_STOP);
2556 stdID(wxID_INDEX);
2557 stdID(wxID_BOLD);
2558 stdID(wxID_ITALIC);
2559 stdID(wxID_JUSTIFY_CENTER);
2560 stdID(wxID_JUSTIFY_FILL);
2561 stdID(wxID_JUSTIFY_RIGHT);
2562 stdID(wxID_JUSTIFY_LEFT);
2563 stdID(wxID_UNDERLINE);
2564 stdID(wxID_INDENT);
2565 stdID(wxID_UNINDENT);
2566 stdID(wxID_ZOOM_100);
2567 stdID(wxID_ZOOM_FIT);
2568 stdID(wxID_ZOOM_IN);
2569 stdID(wxID_ZOOM_OUT);
2570 stdID(wxID_UNDELETE);
2571 stdID(wxID_REVERT_TO_SAVED);
2572 stdID(wxID_SYSTEM_MENU);
2573 stdID(wxID_CLOSE_FRAME);
2574 stdID(wxID_MOVE_FRAME);
2575 stdID(wxID_RESIZE_FRAME);
2576 stdID(wxID_MAXIMIZE_FRAME);
2577 stdID(wxID_ICONIZE_FRAME);
2578 stdID(wxID_RESTORE_FRAME);
6b1eedc1
VZ
2579 stdID(wxID_CDROM);
2580 stdID(wxID_CONVERT);
2581 stdID(wxID_EXECUTE);
2582 stdID(wxID_FLOPPY);
2583 stdID(wxID_HARDDISK);
2584 stdID(wxID_BOTTOM);
2585 stdID(wxID_FIRST);
2586 stdID(wxID_LAST);
2587 stdID(wxID_TOP);
2588 stdID(wxID_INFO);
2589 stdID(wxID_JUMP_TO);
2590 stdID(wxID_NETWORK);
2591 stdID(wxID_SELECT_COLOR);
2592 stdID(wxID_SELECT_FONT);
2593 stdID(wxID_SORT_ASCENDING);
2594 stdID(wxID_SORT_DESCENDING);
2595 stdID(wxID_SPELL_CHECK);
2596 stdID(wxID_STRIKETHROUGH);
c369d4f1 2597
13de23f6
VS
2598#undef stdID
2599}
78d14f80 2600
a58804ea 2601} // anonymous namespace
78d14f80
VS
2602
2603
a58804ea
VZ
2604/*static*/
2605int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found)
2606{
2607 if ( !gs_stdIDsAdded )
2608 {
2609 gs_stdIDsAdded = true;
2610 AddStdXRCID_Records();
2611 }
2612
2613 return XRCID_Lookup(str_id, value_if_not_found);
2614}
2615
2616/* static */
2617wxString wxXmlResource::FindXRCIDById(int numId)
2618{
2619 for ( int i = 0; i < XRCID_TABLE_SIZE; i++ )
2620 {
2621 for ( XRCID_record *rec = XRCID_Records[i]; rec; rec = rec->next )
2622 {
2623 if ( rec->id == numId )
2624 return wxString(rec->key);
2625 }
2626 }
2627
2628 return wxString();
2629}
2630
0526c8cc 2631/* static */
e7cad4b7 2632void wxIdRangeManager::RemoveXRCIDEntry(const wxString& idstr)
0526c8cc 2633{
e7cad4b7
VZ
2634 const char *str_id = idstr.mb_str();
2635
d807030e 2636 const unsigned index = XRCIdHash(str_id);
0526c8cc
VZ
2637
2638 XRCID_record **p_previousrec = &XRCID_Records[index];
2639 for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
2640 {
2641 if (wxStrcmp(rec->key, str_id) == 0)
2642 {
2643 // Found the item to be removed so delete its record; but first
adf1edd9
VZ
2644 // remove it from the linked list.
2645 *p_previousrec = rec->next;
0526c8cc
VZ
2646 free(rec->key);
2647 delete rec;
2648 return;
2649 }
adf1edd9
VZ
2650
2651 p_previousrec = &rec->next;
0526c8cc
VZ
2652 }
2653}
2654
a58804ea
VZ
2655static void CleanXRCID_Record(XRCID_record *rec)
2656{
2657 if (rec)
2658 {
2659 CleanXRCID_Record(rec->next);
2660
2661 free(rec->key);
2662 delete rec;
2663 }
2664}
2665
2666static void CleanXRCID_Records()
2667{
2668 for (int i = 0; i < XRCID_TABLE_SIZE; i++)
2669 {
2670 CleanXRCID_Record(XRCID_Records[i]);
2671 XRCID_Records[i] = NULL;
2672 }
2673
2674 gs_stdIDsAdded = false;
2675}
78d14f80
VS
2676
2677
819559b2
VS
2678//-----------------------------------------------------------------------------
2679// module and globals
2680//-----------------------------------------------------------------------------
78d14f80 2681
fd230129
VZ
2682// normally we would do the cleanup from wxXmlResourceModule::OnExit() but it
2683// can happen that some XRC records have been created because of the use of
2684// XRCID() in event tables, which happens during static objects initialization,
2685// but then the application initialization failed and so the wx modules were
2686// neither initialized nor cleaned up -- this static object does the cleanup in
2687// this case
2688static struct wxXRCStaticCleanup
2689{
2690 ~wxXRCStaticCleanup() { CleanXRCID_Records(); }
2691} s_staticCleanup;
2692
78d14f80
VS
2693class wxXmlResourceModule: public wxModule
2694{
2695DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
2696public:
2697 wxXmlResourceModule() {}
824e8eaa
VS
2698 bool OnInit()
2699 {
2b5f62a0 2700 wxXmlResource::AddSubclassFactory(new wxXmlSubclassFactoryCXX);
f80ea77b 2701 return true;
824e8eaa 2702 }
78d14f80
VS
2703 void OnExit()
2704 {
1542c42e 2705 delete wxXmlResource::Set(NULL);
0526c8cc 2706 delete wxIdRangeManager::Set(NULL);
461932ae 2707 if(wxXmlResource::ms_subclassFactories)
eb2d0d23
VS
2708 {
2709 for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
2710 i != wxXmlResource::ms_subclassFactories->end(); ++i )
2711 {
2712 delete *i;
2713 }
2714 wxDELETE(wxXmlResource::ms_subclassFactories);
2715 }
5ed345b7 2716 CleanXRCID_Records();
78d14f80
VS
2717 }
2718};
2719
2720IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)
2721
2722
2723// When wxXml is loaded dynamically after the application is already running
2724// then the built-in module system won't pick this one up. Add it manually.
2725void wxXmlInitResourceModule()
2726{
2727 wxModule* module = new wxXmlResourceModule;
2728 module->Init();
2729 wxModule::RegisterModule(module);
2730}
a1e4ec87
VS
2731
2732#endif // wxUSE_XRC