]> git.saurik.com Git - wxWidgets.git/blob - src/xrc/xmlres.cpp
detect and report errors in XRC specification of grid sizers
[wxWidgets.git] / src / xrc / xmlres.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/xrc/xmlres.cpp
3 // Purpose: XRC resources
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
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_XRC
19
20 #include "wx/xrc/xmlres.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/intl.h"
24 #include "wx/log.h"
25 #include "wx/panel.h"
26 #include "wx/frame.h"
27 #include "wx/dialog.h"
28 #include "wx/settings.h"
29 #include "wx/bitmap.h"
30 #include "wx/image.h"
31 #include "wx/module.h"
32 #include "wx/wxcrtvararg.h"
33 #endif
34
35 #ifndef __WXWINCE__
36 #include <locale.h>
37 #endif
38
39 #include "wx/vector.h"
40 #include "wx/wfstream.h"
41 #include "wx/filesys.h"
42 #include "wx/filename.h"
43 #include "wx/tokenzr.h"
44 #include "wx/fontenum.h"
45 #include "wx/fontmap.h"
46 #include "wx/artprov.h"
47 #include "wx/dir.h"
48 #include "wx/xml/xml.h"
49
50
51 class wxXmlResourceDataRecord
52 {
53 public:
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
68 class wxXmlResourceDataRecords : public wxVector<wxXmlResourceDataRecord*>
69 {
70 // this is a class so that it can be forward-declared
71 };
72
73 namespace
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
80 inline 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
89
90 wxXmlResource *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
106 wxXmlResource::wxXmlResource(int flags, const wxString& domain)
107 {
108 m_flags = flags;
109 m_version = -1;
110 m_data = new wxXmlResourceDataRecords;
111 SetDomain(domain);
112 }
113
114 wxXmlResource::wxXmlResource(const wxString& filemask, int flags, const wxString& domain)
115 {
116 m_flags = flags;
117 m_version = -1;
118 m_data = new wxXmlResourceDataRecords;
119 SetDomain(domain);
120 Load(filemask);
121 }
122
123 wxXmlResource::~wxXmlResource()
124 {
125 ClearHandlers();
126
127 for ( wxXmlResourceDataRecords::iterator i = m_data->begin();
128 i != m_data->end(); ++i )
129 {
130 delete *i;
131 }
132 delete m_data;
133 }
134
135 void wxXmlResource::SetDomain(const wxString& domain)
136 {
137 m_domain = domain;
138 }
139
140
141 /* static */
142 wxString 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 */
172 bool 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
181 bool wxXmlResource::LoadFile(const wxFileName& file)
182 {
183 #if wxUSE_FILESYSTEM
184 return Load(wxFileSystem::FileNameToURL(file));
185 #else
186 return Load(file.GetFullPath());
187 #endif
188 }
189
190 bool 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
206 bool wxXmlResource::Load(const wxString& filemask_)
207 {
208 wxString filemask = ConvertFileNameToURL(filemask_);
209
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
218 wxString fnd = wxXmlFindFirst;
219 if ( fnd.empty() )
220 {
221 wxLogError(_("Cannot load resources from '%s'."), filemask);
222 return false;
223 }
224
225 while (!fnd.empty())
226 {
227 #if wxUSE_FILESYSTEM
228 if ( IsArchive(fnd) )
229 {
230 if ( !Load(fnd + wxT("#zip:*.xrc")) )
231 return false;
232 }
233 else // a single resource URL
234 #endif // wxUSE_FILESYSTEM
235 {
236 wxXmlResourceDataRecord *drec = new wxXmlResourceDataRecord;
237 drec->File = fnd;
238 Data().push_back(drec);
239 }
240
241 fnd = wxXmlFindNext;
242 }
243 # undef wxXmlFindFirst
244 # undef wxXmlFindNext
245
246 return UpdateResources();
247 }
248
249 bool 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;
262 for ( wxXmlResourceDataRecords::iterator i = Data().begin();
263 i != Data().end(); ++i )
264 {
265 #if wxUSE_FILESYSTEM
266 if ( isArchive )
267 {
268 if ( (*i)->File.StartsWith(fnd) )
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 {
275 if ( (*i)->File == fnd )
276 {
277 delete *i;
278 Data().erase(i);
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
290
291 IMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject)
292
293 void wxXmlResource::AddHandler(wxXmlResourceHandler *handler)
294 {
295 m_handlers.push_back(handler);
296 handler->SetParentResource(this);
297 }
298
299 void wxXmlResource::InsertHandler(wxXmlResourceHandler *handler)
300 {
301 m_handlers.insert(m_handlers.begin(), handler);
302 handler->SetParentResource(this);
303 }
304
305
306
307 void wxXmlResource::ClearHandlers()
308 {
309 for ( wxVector<wxXmlResourceHandler*>::iterator i = m_handlers.begin();
310 i != m_handlers.end(); ++i )
311 delete *i;
312 m_handlers.clear();
313 }
314
315
316 wxMenu *wxXmlResource::LoadMenu(const wxString& name)
317 {
318 return (wxMenu*)CreateResFromNode(FindResource(name, wxT("wxMenu")), NULL, NULL);
319 }
320
321
322
323 wxMenuBar *wxXmlResource::LoadMenuBar(wxWindow *parent, const wxString& name)
324 {
325 return (wxMenuBar*)CreateResFromNode(FindResource(name, wxT("wxMenuBar")), parent, NULL);
326 }
327
328
329
330 #if wxUSE_TOOLBAR
331 wxToolBar *wxXmlResource::LoadToolBar(wxWindow *parent, const wxString& name)
332 {
333 return (wxToolBar*)CreateResFromNode(FindResource(name, wxT("wxToolBar")), parent, NULL);
334 }
335 #endif
336
337
338 wxDialog *wxXmlResource::LoadDialog(wxWindow *parent, const wxString& name)
339 {
340 return (wxDialog*)CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, NULL);
341 }
342
343 bool wxXmlResource::LoadDialog(wxDialog *dlg, wxWindow *parent, const wxString& name)
344 {
345 return CreateResFromNode(FindResource(name, wxT("wxDialog")), parent, dlg) != NULL;
346 }
347
348
349
350 wxPanel *wxXmlResource::LoadPanel(wxWindow *parent, const wxString& name)
351 {
352 return (wxPanel*)CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, NULL);
353 }
354
355 bool wxXmlResource::LoadPanel(wxPanel *panel, wxWindow *parent, const wxString& name)
356 {
357 return CreateResFromNode(FindResource(name, wxT("wxPanel")), parent, panel) != NULL;
358 }
359
360 wxFrame *wxXmlResource::LoadFrame(wxWindow* parent, const wxString& name)
361 {
362 return (wxFrame*)CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, NULL);
363 }
364
365 bool wxXmlResource::LoadFrame(wxFrame* frame, wxWindow *parent, const wxString& name)
366 {
367 return CreateResFromNode(FindResource(name, wxT("wxFrame")), parent, frame) != NULL;
368 }
369
370 wxBitmap 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
380 wxIcon 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
390
391 wxObject *wxXmlResource::LoadObject(wxWindow *parent, const wxString& name, const wxString& classname)
392 {
393 return CreateResFromNode(FindResource(name, classname), parent, NULL);
394 }
395
396 bool 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
402 bool 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 {
410 wxLogError("Cannot find container for unknown control '%s'.", name);
411 return false;
412 }
413 return control->Reparent(container);
414 }
415
416
417 static void ProcessPlatformProperty(wxXmlNode *node)
418 {
419 wxString s;
420 bool isok;
421
422 wxXmlNode *c = node->GetChildren();
423 while (c)
424 {
425 isok = false;
426 if (!c->GetAttribute(wxT("platform"), &s))
427 isok = true;
428 else
429 {
430 wxStringTokenizer tkn(s, wxT(" |"));
431
432 while (tkn.HasMoreTokens())
433 {
434 s = tkn.GetNextToken();
435 #ifdef __WINDOWS__
436 if (s == wxT("win")) isok = true;
437 #endif
438 #if defined(__MAC__) || defined(__APPLE__)
439 if (s == wxT("mac")) isok = true;
440 #elif defined(__UNIX__)
441 if (s == wxT("unix")) isok = true;
442 #endif
443 #ifdef __OS2__
444 if (s == wxT("os2")) isok = true;
445 #endif
446
447 if (isok)
448 break;
449 }
450 }
451
452 if (isok)
453 {
454 ProcessPlatformProperty(c);
455 c = c->GetNext();
456 }
457 else
458 {
459 wxXmlNode *c2 = c->GetNext();
460 node->RemoveChild(c);
461 delete c;
462 c = c2;
463 }
464 }
465 }
466
467
468
469 bool wxXmlResource::UpdateResources()
470 {
471 bool rt = true;
472 bool modif;
473 # if wxUSE_FILESYSTEM
474 wxFSFile *file = NULL;
475 wxUnusedVar(file);
476 wxFileSystem fsys;
477 # endif
478
479 wxString encoding(wxT("UTF-8"));
480 #if !wxUSE_UNICODE && wxUSE_INTL
481 if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 )
482 {
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.
486 encoding = wxLocale::GetSystemEncodingName();
487 }
488 #endif
489
490 for ( wxXmlResourceDataRecords::iterator i = Data().begin();
491 i != Data().end(); ++i )
492 {
493 wxXmlResourceDataRecord* const rec = *i;
494
495 modif = (rec->Doc == NULL);
496
497 if (!modif && !(m_flags & wxXRC_NO_RELOADING))
498 {
499 # if wxUSE_FILESYSTEM
500 file = fsys.OpenFile(rec->File);
501 # if wxUSE_DATETIME
502 modif = file && file->GetModificationTime() > rec->Time;
503 # else // wxUSE_DATETIME
504 modif = true;
505 # endif // wxUSE_DATETIME
506 if (!file)
507 {
508 wxLogError(_("Cannot open file '%s'."), rec->File);
509 rt = false;
510 }
511 wxDELETE(file);
512 wxUnusedVar(file);
513 # else // wxUSE_FILESYSTEM
514 # if wxUSE_DATETIME
515 modif = wxDateTime(wxFileModificationTime(rec->File)) > rec->Time;
516 # else // wxUSE_DATETIME
517 modif = true;
518 # endif // wxUSE_DATETIME
519 # endif // wxUSE_FILESYSTEM
520 }
521
522 if (modif)
523 {
524 wxLogTrace(_T("xrc"), _T("opening file '%s'"), rec->File);
525
526 wxInputStream *stream = NULL;
527
528 # if wxUSE_FILESYSTEM
529 file = fsys.OpenFile(rec->File);
530 if (file)
531 stream = file->GetStream();
532 # else
533 stream = new wxFileInputStream(rec->File);
534 # endif
535
536 if (stream)
537 {
538 delete rec->Doc;
539 rec->Doc = new wxXmlDocument;
540 }
541 if (!stream || !stream->IsOk() || !rec->Doc->Load(*stream, encoding))
542 {
543 wxLogError(_("Cannot load resources from file '%s'."),
544 rec->File);
545 wxDELETE(rec->Doc);
546 rt = false;
547 }
548 else if (rec->Doc->GetRoot()->GetName() != wxT("resource"))
549 {
550 ReportError
551 (
552 rec->Doc->GetRoot(),
553 "invalid XRC resource, doesn't have root node <resource>"
554 );
555 wxDELETE(rec->Doc);
556 rt = false;
557 }
558 else
559 {
560 long version;
561 int v1, v2, v3, v4;
562 wxString verstr = rec->Doc->GetRoot()->GetAttribute(
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)
572 {
573 wxLogError("Resource files must have same version number.");
574 rt = false;
575 }
576
577 ProcessPlatformProperty(rec->Doc->GetRoot());
578 #if wxUSE_DATETIME
579 #if wxUSE_FILESYSTEM
580 rec->Time = file->GetModificationTime();
581 #else // wxUSE_FILESYSTEM
582 rec->Time = wxDateTime(wxFileModificationTime(rec->File));
583 #endif // wxUSE_FILESYSTEM
584 #endif // wxUSE_DATETIME
585 }
586
587 # if wxUSE_FILESYSTEM
588 wxDELETE(file);
589 wxUnusedVar(file);
590 # else
591 wxDELETE(stream);
592 # endif
593 }
594 }
595
596 return rt;
597 }
598
599 wxXmlNode *wxXmlResource::DoFindResource(wxXmlNode *parent,
600 const wxString& name,
601 const wxString& classname,
602 bool recursive) const
603 {
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 {
610 if ( IsObjectNode(node) && node->GetAttribute(wxS("name")) == name )
611 {
612 // empty class name matches everything
613 if ( classname.empty() )
614 return node;
615
616 wxString cls(node->GetAttribute(wxS("class")));
617
618 // object_ref may not have 'class' attribute:
619 if (cls.empty() && node->GetName() == wxS("object_ref"))
620 {
621 wxString refName = node->GetAttribute(wxS("ref"));
622 if (refName.empty())
623 continue;
624
625 const wxXmlNode * const refNode = GetResourceNode(refName);
626 if ( refNode )
627 cls = refNode->GetAttribute(wxS("class"));
628 }
629
630 if ( cls == classname )
631 return node;
632 }
633 }
634
635 // then recurse in child nodes
636 if ( recursive )
637 {
638 for (node = parent->GetChildren(); node; node = node->GetNext())
639 {
640 if ( IsObjectNode(node) )
641 {
642 wxXmlNode* found = DoFindResource(node, name, classname, true);
643 if ( found )
644 return found;
645 }
646 }
647 }
648
649 return NULL;
650 }
651
652 wxXmlNode *wxXmlResource::FindResource(const wxString& name,
653 const wxString& classname,
654 bool recursive)
655 {
656 wxString path;
657 wxXmlNode * const
658 node = GetResourceNodeAndLocation(name, classname, recursive, &path);
659
660 if ( !node )
661 {
662 ReportError
663 (
664 NULL,
665 wxString::Format
666 (
667 "XRC resource \"%s\" (class \"%s\") not found",
668 name, classname
669 )
670 );
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
685 wxXmlNode *
686 wxXmlResource::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();
694
695 for ( wxXmlResourceDataRecords::const_iterator f = Data().begin();
696 f != Data().end(); ++f )
697 {
698 wxXmlResourceDataRecord *const rec = *f;
699 wxXmlDocument * const doc = rec->Doc;
700 if ( !doc || !doc->GetRoot() )
701 continue;
702
703 wxXmlNode * const
704 found = DoFindResource(doc->GetRoot(), name, classname, recursive);
705 if ( found )
706 {
707 if ( path )
708 *path = rec->File;
709
710 return found;
711 }
712 }
713
714 return NULL;
715 }
716
717 static void MergeNodes(wxXmlNode& dest, wxXmlNode& with)
718 {
719 // Merge attributes:
720 for ( wxXmlAttribute *attr = with.GetAttributes();
721 attr; attr = attr->GetNext() )
722 {
723 wxXmlAttribute *dattr;
724 for (dattr = dest.GetAttributes(); dattr; dattr = dattr->GetNext())
725 {
726
727 if ( dattr->GetName() == attr->GetName() )
728 {
729 dattr->SetValue(attr->GetValue());
730 break;
731 }
732 }
733
734 if ( !dattr )
735 dest.AddAttribute(attr->GetName(), attr->GetValue());
736 }
737
738 // Merge child nodes:
739 for (wxXmlNode* node = with.GetChildren(); node; node = node->GetNext())
740 {
741 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
742 wxXmlNode *dnode;
743
744 for (dnode = dest.GetChildren(); dnode; dnode = dnode->GetNext() )
745 {
746 if ( dnode->GetName() == node->GetName() &&
747 dnode->GetAttribute(wxT("name"), wxEmptyString) == name &&
748 dnode->GetType() == node->GetType() )
749 {
750 MergeNodes(*dnode, *node);
751 break;
752 }
753 }
754
755 if ( !dnode )
756 {
757 static const wxChar *AT_END = wxT("end");
758 wxString insert_pos = node->GetAttribute(wxT("insert_at"), AT_END);
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 }
768 }
769
770 if ( dest.GetType() == wxXML_TEXT_NODE && with.GetContent().length() )
771 dest.SetContent(with.GetContent());
772 }
773
774 wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent,
775 wxObject *instance,
776 wxXmlResourceHandler *handlerToUse)
777 {
778 if (node == NULL) return NULL;
779
780 // handling of referenced resource
781 if ( node->GetName() == wxT("object_ref") )
782 {
783 wxString refName = node->GetAttribute(wxT("ref"), wxEmptyString);
784 wxXmlNode* refNode = FindResource(refName, wxEmptyString, true);
785
786 if ( !refNode )
787 {
788 ReportError
789 (
790 node,
791 wxString::Format
792 (
793 "referenced object node with ref=\"%s\" not found",
794 refName
795 )
796 );
797 return NULL;
798 }
799
800 wxXmlNode copy(*refNode);
801 MergeNodes(copy, *node);
802
803 return CreateResFromNode(&copy, parent, instance);
804 }
805
806 if (handlerToUse)
807 {
808 if (handlerToUse->CanHandle(node))
809 {
810 return handlerToUse->CreateResource(node, parent, instance);
811 }
812 }
813 else if (node->GetName() == wxT("object"))
814 {
815 for ( wxVector<wxXmlResourceHandler*>::iterator h = m_handlers.begin();
816 h != m_handlers.end(); ++h )
817 {
818 wxXmlResourceHandler *handler = *h;
819 if (handler->CanHandle(node))
820 return handler->CreateResource(node, parent, instance);
821 }
822 }
823
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 );
834 return NULL;
835 }
836
837
838 class wxXmlSubclassFactories : public wxVector<wxXmlSubclassFactory*>
839 {
840 // this is a class so that it can be forward-declared
841 };
842
843 wxXmlSubclassFactories *wxXmlResource::ms_subclassFactories = NULL;
844
845 /*static*/ void wxXmlResource::AddSubclassFactory(wxXmlSubclassFactory *factory)
846 {
847 if (!ms_subclassFactories)
848 {
849 ms_subclassFactories = new wxXmlSubclassFactories;
850 }
851 ms_subclassFactories->push_back(factory);
852 }
853
854 class wxXmlSubclassFactoryCXX : public wxXmlSubclassFactory
855 {
856 public:
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
872
873 wxXmlResourceHandler::wxXmlResourceHandler()
874 : m_node(NULL), m_parent(NULL), m_instance(NULL),
875 m_parentAsWindow(NULL)
876 {}
877
878
879
880 wxObject *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;
885 wxWindow *myParentAW = m_parentAsWindow;
886
887 m_instance = instance;
888 if (!m_instance && node->HasAttribute(wxT("subclass")) &&
889 !(m_resource->GetFlags() & wxXRC_NO_SUBCLASSING))
890 {
891 wxString subclass = node->GetAttribute(wxT("subclass"), wxEmptyString);
892 if (!subclass.empty())
893 {
894 for (wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
895 i != wxXmlResource::ms_subclassFactories->end(); ++i)
896 {
897 m_instance = (*i)->Create(subclass);
898 if (m_instance)
899 break;
900 }
901
902 if (!m_instance)
903 {
904 wxString name = node->GetAttribute(wxT("name"), wxEmptyString);
905 ReportError
906 (
907 node,
908 wxString::Format
909 (
910 "subclass \"%s\" not found for resource \"%s\", not subclassing",
911 subclass, name
912 )
913 );
914 }
915 }
916 }
917
918 m_node = node;
919 m_class = node->GetAttribute(wxT("class"), wxEmptyString);
920 m_parent = parent;
921 m_parentAsWindow = wxDynamicCast(m_parent, wxWindow);
922
923 wxObject *returned = DoCreateResource();
924
925 m_node = myNode;
926 m_class = myClass;
927 m_parent = myParent; m_parentAsWindow = myParentAW;
928 m_instance = myInstance;
929
930 return returned;
931 }
932
933
934 void wxXmlResourceHandler::AddStyle(const wxString& name, int value)
935 {
936 m_styleNames.Add(name);
937 m_styleValues.Add(value);
938 }
939
940
941
942 void wxXmlResourceHandler::AddWindowStyles()
943 {
944 XRC_ADD_STYLE(wxCLIP_CHILDREN);
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
954 XRC_ADD_STYLE(wxTRANSPARENT_WINDOW);
955 XRC_ADD_STYLE(wxWANTS_CHARS);
956 XRC_ADD_STYLE(wxTAB_TRAVERSAL);
957 XRC_ADD_STYLE(wxNO_FULL_REPAINT_ON_RESIZE);
958 XRC_ADD_STYLE(wxFULL_REPAINT_ON_RESIZE);
959 XRC_ADD_STYLE(wxALWAYS_SHOW_SB);
960 XRC_ADD_STYLE(wxWS_EX_BLOCK_EVENTS);
961 XRC_ADD_STYLE(wxWS_EX_VALIDATE_RECURSIVELY);
962 }
963
964
965
966 bool wxXmlResourceHandler::HasParam(const wxString& param)
967 {
968 return (GetParamNode(param) != NULL);
969 }
970
971
972 int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
973 {
974 wxString s = GetParamValue(param);
975
976 if (!s) return defaults;
977
978 wxStringTokenizer tkn(s, wxT("| \t\n"), wxTOKEN_STRTOK);
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)
987 {
988 style |= m_styleValues[index];
989 }
990 else
991 {
992 ReportParamError
993 (
994 param,
995 wxString::Format("unknown style flag \"%s\"", fl)
996 );
997 }
998 }
999 return style;
1000 }
1001
1002
1003
1004 wxString wxXmlResourceHandler::GetText(const wxString& param, bool translate)
1005 {
1006 wxXmlNode *parNode = GetParamNode(param);
1007 wxString str1(GetNodeContent(parNode));
1008 wxString str2;
1009
1010 // "\\" wasn't translated to "\" prior to 2.5.3.0:
1011 const bool escapeBackslash = (m_resource->CompareVersion(2,5,3,0) >= 0);
1012
1013 // VS: First version of XRC resources used $ instead of & (which is
1014 // illegal in XML), but later I realized that '_' fits this purpose
1015 // much better (because &File means "File with F underlined").
1016 const wxChar amp_char = (m_resource->CompareVersion(2,3,0,1) < 0)
1017 ? '$' : '_';
1018
1019 for ( wxString::const_iterator dt = str1.begin(); dt != str1.end(); ++dt )
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..."):
1023 if ( *dt == amp_char )
1024 {
1025 if ( *(++dt) == amp_char )
1026 str2 << amp_char;
1027 else
1028 str2 << wxT('&') << *dt;
1029 }
1030 // Remap \n to CR, \r to LF, \t to TAB, \\ to \:
1031 else if ( *dt == wxT('\\') )
1032 {
1033 switch ( (*(++dt)).GetValue() )
1034 {
1035 case wxT('n'):
1036 str2 << wxT('\n');
1037 break;
1038
1039 case wxT('t'):
1040 str2 << wxT('\t');
1041 break;
1042
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:
1049 if ( escapeBackslash )
1050 {
1051 str2 << wxT('\\');
1052 break;
1053 }
1054 // else fall-through to default: branch below
1055
1056 default:
1057 str2 << wxT('\\') << *dt;
1058 break;
1059 }
1060 }
1061 else
1062 {
1063 str2 << *dt;
1064 }
1065 }
1066
1067 if (m_resource->GetFlags() & wxXRC_USE_LOCALE)
1068 {
1069 if (translate && parNode &&
1070 parNode->GetAttribute(wxT("translate"), wxEmptyString) != wxT("0"))
1071 {
1072 return wxGetTranslation(str2, m_resource->GetDomain());
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:
1081 return wxString(str2.wc_str(wxConvUTF8), wxConvLocal);
1082 #endif
1083 }
1084 }
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;
1090 }
1091
1092
1093
1094 long 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 }
1104
1105 float wxXmlResourceHandler::GetFloat(const wxString& param, float defaultv)
1106 {
1107 wxString str = GetParamValue(param);
1108
1109 #if wxUSE_INTL
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));
1117 #endif // wxUSE_INTL
1118
1119 double value;
1120 if (!str.ToDouble(&value))
1121 value = defaultv;
1122
1123 return wx_truncate_cast(float, value);
1124 }
1125
1126
1127 int wxXmlResourceHandler::GetID()
1128 {
1129 return wxXmlResource::GetXRCID(GetName());
1130 }
1131
1132
1133
1134 wxString wxXmlResourceHandler::GetName()
1135 {
1136 return m_node->GetAttribute(wxT("name"), wxT("-1"));
1137 }
1138
1139
1140
1141 bool wxXmlResourceHandler::GetBoolAttr(const wxString& attr, bool defaultv)
1142 {
1143 wxString v;
1144 return m_node->GetAttribute(attr, &v) ? v == '1' : defaultv;
1145 }
1146
1147 bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv)
1148 {
1149 const wxString v = GetParamValue(param);
1150
1151 return v.empty() ? defaultv : (v == '1');
1152 }
1153
1154
1155 static 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 }
1203
1204 wxColour wxXmlResourceHandler::GetColour(const wxString& param, const wxColour& defaultv)
1205 {
1206 wxString v = GetParamValue(param);
1207
1208 if ( v.empty() )
1209 return defaultv;
1210
1211 wxColour clr;
1212
1213 // wxString -> wxColour conversion
1214 if (!clr.Set(v))
1215 {
1216 // the colour doesn't use #RRGGBB format, check if it is symbolic
1217 // colour name:
1218 clr = GetSystemColour(v);
1219 if (clr.Ok())
1220 return clr;
1221
1222 ReportParamError
1223 (
1224 param,
1225 wxString::Format("incorrect colour specification \"%s\"", v)
1226 );
1227 return wxNullColour;
1228 }
1229
1230 return clr;
1231 }
1232
1233
1234
1235 wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
1236 const wxArtClient& defaultArtClient,
1237 wxSize size)
1238 {
1239 /* If the bitmap is specified as stock item, query wxArtProvider for it: */
1240 wxXmlNode *bmpNode = GetParamNode(param);
1241 if ( bmpNode )
1242 {
1243 wxString sid = bmpNode->GetAttribute(wxT("stock_id"), wxEmptyString);
1244 if ( !sid.empty() )
1245 {
1246 wxString scl = bmpNode->GetAttribute(wxT("stock_client"), wxEmptyString);
1247 if (scl.empty())
1248 scl = defaultArtClient;
1249 else
1250 scl = wxART_MAKE_CLIENT_ID_FROM_STR(scl);
1251
1252 wxBitmap stockArt =
1253 wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(sid),
1254 scl, size);
1255 if ( stockArt.Ok() )
1256 return stockArt;
1257 }
1258 }
1259
1260 /* ...or load the bitmap from file: */
1261 wxString name = GetParamValue(param);
1262 if (name.empty()) return wxNullBitmap;
1263 #if wxUSE_FILESYSTEM
1264 wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
1265 if (fsfile == NULL)
1266 {
1267 ReportParamError
1268 (
1269 param,
1270 wxString::Format("cannot open bitmap resource \"%s\"", name)
1271 );
1272 return wxNullBitmap;
1273 }
1274 wxImage img(*(fsfile->GetStream()));
1275 delete fsfile;
1276 #else
1277 wxImage img(name);
1278 #endif
1279
1280 if (!img.Ok())
1281 {
1282 ReportParamError
1283 (
1284 param,
1285 wxString::Format("cannot create bitmap from \"%s\"", name)
1286 );
1287 return wxNullBitmap;
1288 }
1289 if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
1290 return wxBitmap(img);
1291 }
1292
1293
1294 wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
1295 const wxArtClient& defaultArtClient,
1296 wxSize size)
1297 {
1298 wxIcon icon;
1299 icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size));
1300 return icon;
1301 }
1302
1303
1304
1305 wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
1306 {
1307 wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!"));
1308
1309 wxXmlNode *n = m_node->GetChildren();
1310
1311 while (n)
1312 {
1313 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
1314 {
1315 // TODO: check that there are no other properties/parameters with
1316 // the same name and log an error if there are (can't do this
1317 // right now as I'm not sure if it's not going to break code
1318 // using this function in unintentional way (i.e. for
1319 // accessing other things than properties), for example
1320 // wxBitmapComboBoxXmlHandler almost surely does
1321 return n;
1322 }
1323 n = n->GetNext();
1324 }
1325 return NULL;
1326 }
1327
1328 bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
1329 {
1330 return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
1331 }
1332
1333
1334
1335 wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
1336 {
1337 wxXmlNode *n = node;
1338 if (n == NULL) return wxEmptyString;
1339 n = n->GetChildren();
1340
1341 while (n)
1342 {
1343 if (n->GetType() == wxXML_TEXT_NODE ||
1344 n->GetType() == wxXML_CDATA_SECTION_NODE)
1345 return n->GetContent();
1346 n = n->GetNext();
1347 }
1348 return wxEmptyString;
1349 }
1350
1351
1352
1353 wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
1354 {
1355 if (param.empty())
1356 return GetNodeContent(m_node);
1357 else
1358 return GetNodeContent(GetParamNode(param));
1359 }
1360
1361
1362
1363 wxSize wxXmlResourceHandler::GetSize(const wxString& param,
1364 wxWindow *windowToUse)
1365 {
1366 wxString s = GetParamValue(param);
1367 if (s.empty()) s = wxT("-1,-1");
1368 bool is_dlg;
1369 long sx, sy = 0;
1370
1371 is_dlg = s[s.length()-1] == wxT('d');
1372 if (is_dlg) s.RemoveLast();
1373
1374 if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
1375 !s.AfterLast(wxT(',')).ToLong(&sy))
1376 {
1377 ReportParamError
1378 (
1379 param,
1380 wxString::Format("cannot parse coordinates value \"%s\"", s)
1381 );
1382 return wxDefaultSize;
1383 }
1384
1385 if (is_dlg)
1386 {
1387 if (windowToUse)
1388 {
1389 return wxDLG_UNIT(windowToUse, wxSize(sx, sy));
1390 }
1391 else if (m_parentAsWindow)
1392 {
1393 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, sy));
1394 }
1395 else
1396 {
1397 ReportParamError
1398 (
1399 param,
1400 "cannot convert dialog units: dialog unknown"
1401 );
1402 return wxDefaultSize;
1403 }
1404 }
1405
1406 return wxSize(sx, sy);
1407 }
1408
1409
1410
1411 wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
1412 {
1413 wxSize sz = GetSize(param);
1414 return wxPoint(sz.x, sz.y);
1415 }
1416
1417
1418
1419 wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
1420 wxCoord defaultv,
1421 wxWindow *windowToUse)
1422 {
1423 wxString s = GetParamValue(param);
1424 if (s.empty()) return defaultv;
1425 bool is_dlg;
1426 long sx;
1427
1428 is_dlg = s[s.length()-1] == wxT('d');
1429 if (is_dlg) s.RemoveLast();
1430
1431 if (!s.ToLong(&sx))
1432 {
1433 ReportParamError
1434 (
1435 param,
1436 wxString::Format("cannot parse dimension value \"%s\"", s)
1437 );
1438 return defaultv;
1439 }
1440
1441 if (is_dlg)
1442 {
1443 if (windowToUse)
1444 {
1445 return wxDLG_UNIT(windowToUse, wxSize(sx, 0)).x;
1446 }
1447 else if (m_parentAsWindow)
1448 {
1449 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, 0)).x;
1450 }
1451 else
1452 {
1453 ReportParamError
1454 (
1455 param,
1456 "cannot convert dialog units: dialog unknown"
1457 );
1458 return defaultv;
1459 }
1460 }
1461
1462 return sx;
1463 }
1464
1465
1466 // Get system font index using indexname
1467 static wxFont GetSystemFont(const wxString& name)
1468 {
1469 if (!name.empty())
1470 {
1471 #define SYSFNT(fnt) \
1472 if (name == _T(#fnt)) return wxSystemSettings::GetFont(fnt);
1473 SYSFNT(wxSYS_OEM_FIXED_FONT)
1474 SYSFNT(wxSYS_ANSI_FIXED_FONT)
1475 SYSFNT(wxSYS_ANSI_VAR_FONT)
1476 SYSFNT(wxSYS_SYSTEM_FONT)
1477 SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
1478 SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
1479 SYSFNT(wxSYS_DEFAULT_GUI_FONT)
1480 #undef SYSFNT
1481 }
1482
1483 return wxNullFont;
1484 }
1485
1486 wxFont wxXmlResourceHandler::GetFont(const wxString& param)
1487 {
1488 wxXmlNode *font_node = GetParamNode(param);
1489 if (font_node == NULL)
1490 {
1491 ReportError(
1492 wxString::Format("cannot find font node \"%s\"", param));
1493 return wxNullFont;
1494 }
1495
1496 wxXmlNode *oldnode = m_node;
1497 m_node = font_node;
1498
1499 // font attributes:
1500
1501 // size
1502 int isize = -1;
1503 bool hasSize = HasParam(wxT("size"));
1504 if (hasSize)
1505 isize = GetLong(wxT("size"), -1);
1506
1507 // style
1508 int istyle = wxNORMAL;
1509 bool hasStyle = HasParam(wxT("style"));
1510 if (hasStyle)
1511 {
1512 wxString style = GetParamValue(wxT("style"));
1513 if (style == wxT("italic"))
1514 istyle = wxITALIC;
1515 else if (style == wxT("slant"))
1516 istyle = wxSLANT;
1517 }
1518
1519 // weight
1520 int iweight = wxNORMAL;
1521 bool hasWeight = HasParam(wxT("weight"));
1522 if (hasWeight)
1523 {
1524 wxString weight = GetParamValue(wxT("weight"));
1525 if (weight == wxT("bold"))
1526 iweight = wxBOLD;
1527 else if (weight == wxT("light"))
1528 iweight = wxLIGHT;
1529 }
1530
1531 // underline
1532 bool hasUnderlined = HasParam(wxT("underlined"));
1533 bool underlined = hasUnderlined ? GetBool(wxT("underlined"), false) : false;
1534
1535 // family and facename
1536 int ifamily = wxDEFAULT;
1537 bool hasFamily = HasParam(wxT("family"));
1538 if (hasFamily)
1539 {
1540 wxString family = GetParamValue(wxT("family"));
1541 if (family == wxT("decorative")) ifamily = wxDECORATIVE;
1542 else if (family == wxT("roman")) ifamily = wxROMAN;
1543 else if (family == wxT("script")) ifamily = wxSCRIPT;
1544 else if (family == wxT("swiss")) ifamily = wxSWISS;
1545 else if (family == wxT("modern")) ifamily = wxMODERN;
1546 else if (family == wxT("teletype")) ifamily = wxTELETYPE;
1547 }
1548
1549
1550 wxString facename;
1551 bool hasFacename = HasParam(wxT("face"));
1552 if (hasFacename)
1553 {
1554 wxString faces = GetParamValue(wxT("face"));
1555 wxStringTokenizer tk(faces, wxT(","));
1556 #if wxUSE_FONTENUM
1557 wxArrayString facenames(wxFontEnumerator::GetFacenames());
1558 while (tk.HasMoreTokens())
1559 {
1560 int index = facenames.Index(tk.GetNextToken(), false);
1561 if (index != wxNOT_FOUND)
1562 {
1563 facename = facenames[index];
1564 break;
1565 }
1566 }
1567 #else // !wxUSE_FONTENUM
1568 // just use the first face name if we can't check its availability:
1569 if (tk.HasMoreTokens())
1570 facename = tk.GetNextToken();
1571 #endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
1572 }
1573
1574 // encoding
1575 wxFontEncoding enc = wxFONTENCODING_DEFAULT;
1576 bool hasEncoding = HasParam(wxT("encoding"));
1577 if (hasEncoding)
1578 {
1579 wxString encoding = GetParamValue(wxT("encoding"));
1580 wxFontMapper mapper;
1581 if (!encoding.empty())
1582 enc = mapper.CharsetToEncoding(encoding);
1583 if (enc == wxFONTENCODING_SYSTEM)
1584 enc = wxFONTENCODING_DEFAULT;
1585 }
1586
1587 // is this font based on a system font?
1588 wxFont font = GetSystemFont(GetParamValue(wxT("sysfont")));
1589
1590 if (font.Ok())
1591 {
1592 if (hasSize && isize != -1)
1593 font.SetPointSize(isize);
1594 else if (HasParam(wxT("relativesize")))
1595 font.SetPointSize(int(font.GetPointSize() *
1596 GetFloat(wxT("relativesize"))));
1597
1598 if (hasStyle)
1599 font.SetStyle(istyle);
1600 if (hasWeight)
1601 font.SetWeight(iweight);
1602 if (hasUnderlined)
1603 font.SetUnderlined(underlined);
1604 if (hasFamily)
1605 font.SetFamily(ifamily);
1606 if (hasFacename)
1607 font.SetFaceName(facename);
1608 if (hasEncoding)
1609 font.SetDefaultEncoding(enc);
1610 }
1611 else // not based on system font
1612 {
1613 font = wxFont(isize == -1 ? wxNORMAL_FONT->GetPointSize() : isize,
1614 ifamily, istyle, iweight,
1615 underlined, facename, enc);
1616 }
1617
1618 m_node = oldnode;
1619 return font;
1620 }
1621
1622
1623 void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
1624 {
1625 //FIXME : add cursor
1626
1627 if (HasParam(wxT("exstyle")))
1628 // Have to OR it with existing style, since
1629 // some implementations (e.g. wxGTK) use the extra style
1630 // during creation
1631 wnd->SetExtraStyle(wnd->GetExtraStyle() | GetStyle(wxT("exstyle")));
1632 if (HasParam(wxT("bg")))
1633 wnd->SetBackgroundColour(GetColour(wxT("bg")));
1634 if (HasParam(wxT("fg")))
1635 wnd->SetForegroundColour(GetColour(wxT("fg")));
1636 if (GetBool(wxT("enabled"), 1) == 0)
1637 wnd->Enable(false);
1638 if (GetBool(wxT("focused"), 0) == 1)
1639 wnd->SetFocus();
1640 if (GetBool(wxT("hidden"), 0) == 1)
1641 wnd->Show(false);
1642 #if wxUSE_TOOLTIPS
1643 if (HasParam(wxT("tooltip")))
1644 wnd->SetToolTip(GetText(wxT("tooltip")));
1645 #endif
1646 if (HasParam(wxT("font")))
1647 wnd->SetFont(GetFont());
1648 if (HasParam(wxT("help")))
1649 wnd->SetHelpText(GetText(wxT("help")));
1650 }
1651
1652
1653 void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
1654 {
1655 for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() )
1656 {
1657 if ( IsObjectNode(n) )
1658 {
1659 m_resource->CreateResFromNode(n, parent, NULL,
1660 this_hnd_only ? this : NULL);
1661 }
1662 }
1663 }
1664
1665
1666 void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode)
1667 {
1668 wxXmlNode *root;
1669 if (rootnode == NULL) root = m_node; else root = rootnode;
1670 wxXmlNode *n = root->GetChildren();
1671
1672 while (n)
1673 {
1674 if (n->GetType() == wxXML_ELEMENT_NODE && CanHandle(n))
1675 {
1676 CreateResource(n, parent, NULL);
1677 }
1678 n = n->GetNext();
1679 }
1680 }
1681
1682
1683 //-----------------------------------------------------------------------------
1684 // errors reporting
1685 //-----------------------------------------------------------------------------
1686
1687 void wxXmlResourceHandler::ReportError(const wxString& message)
1688 {
1689 m_resource->ReportError(m_node, message);
1690 }
1691
1692 void wxXmlResourceHandler::ReportError(wxXmlNode *context,
1693 const wxString& message)
1694 {
1695 m_resource->ReportError(context ? context : m_node, message);
1696 }
1697
1698 void wxXmlResourceHandler::ReportParamError(const wxString& param,
1699 const wxString& message)
1700 {
1701 m_resource->ReportError(GetParamNode(param), message);
1702 }
1703
1704 namespace
1705 {
1706
1707 wxString
1708 GetFileNameFromNode(wxXmlNode *node, const wxXmlResourceDataRecords& files)
1709 {
1710 wxXmlNode *root = node;
1711 while ( root->GetParent() )
1712 root = root->GetParent();
1713
1714 for ( wxXmlResourceDataRecords::const_iterator i = files.begin();
1715 i != files.end(); ++i )
1716 {
1717 if ( (*i)->Doc->GetRoot() == root )
1718 {
1719 return (*i)->File;
1720 }
1721 }
1722
1723 return wxEmptyString; // not found
1724 }
1725
1726 } // anonymous namespace
1727
1728 void wxXmlResource::ReportError(wxXmlNode *context, const wxString& message)
1729 {
1730 if ( !context )
1731 {
1732 DoReportError("", NULL, message);
1733 return;
1734 }
1735
1736 // We need to find out the file that 'context' is part of. Performance of
1737 // this code is not critical, so we simply find the root XML node and
1738 // compare it with all loaded XRC files.
1739 const wxString filename = GetFileNameFromNode(context, Data());
1740
1741 DoReportError(filename, context, message);
1742 }
1743
1744 void wxXmlResource::DoReportError(const wxString& xrcFile, wxXmlNode *position,
1745 const wxString& message)
1746 {
1747 const int line = position ? position->GetLineNumber() : -1;
1748
1749 wxString loc;
1750 if ( !xrcFile.empty() )
1751 loc = xrcFile + ':';
1752 if ( line != -1 )
1753 loc += wxString::Format("%d:", line);
1754 if ( !loc.empty() )
1755 loc += ' ';
1756
1757 wxLogError("XRC error: %s%s", loc, message);
1758 }
1759
1760
1761 //-----------------------------------------------------------------------------
1762 // XRCID implementation
1763 //-----------------------------------------------------------------------------
1764
1765 #define XRCID_TABLE_SIZE 1024
1766
1767
1768 struct XRCID_record
1769 {
1770 /* Hold the id so that once an id is allocated for a name, it
1771 does not get created again by NewControlId at least
1772 until we are done with it */
1773 wxWindowIDRef id;
1774 char *key;
1775 XRCID_record *next;
1776 };
1777
1778 static XRCID_record *XRCID_Records[XRCID_TABLE_SIZE] = {NULL};
1779
1780 static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE)
1781 {
1782 int index = 0;
1783
1784 for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
1785 index %= XRCID_TABLE_SIZE;
1786
1787 XRCID_record *oldrec = NULL;
1788 for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
1789 {
1790 if (wxStrcmp(rec->key, str_id) == 0)
1791 {
1792 return rec->id;
1793 }
1794 oldrec = rec;
1795 }
1796
1797 XRCID_record **rec_var = (oldrec == NULL) ?
1798 &XRCID_Records[index] : &oldrec->next;
1799 *rec_var = new XRCID_record;
1800 (*rec_var)->key = wxStrdup(str_id);
1801 (*rec_var)->next = NULL;
1802
1803 char *end;
1804 if (value_if_not_found != wxID_NONE)
1805 (*rec_var)->id = value_if_not_found;
1806 else
1807 {
1808 int asint = wxStrtol(str_id, &end, 10);
1809 if (*str_id && *end == 0)
1810 {
1811 // if str_id was integer, keep it verbosely:
1812 (*rec_var)->id = asint;
1813 }
1814 else
1815 {
1816 (*rec_var)->id = wxWindowBase::NewControlId();
1817 }
1818 }
1819
1820 return (*rec_var)->id;
1821 }
1822
1823 static void AddStdXRCID_Records();
1824
1825 /*static*/
1826 int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found)
1827 {
1828 static bool s_stdIDsAdded = false;
1829
1830 if ( !s_stdIDsAdded )
1831 {
1832 s_stdIDsAdded = true;
1833 AddStdXRCID_Records();
1834 }
1835
1836 return XRCID_Lookup(str_id, value_if_not_found);
1837 }
1838
1839 /* static */
1840 wxString wxXmlResource::FindXRCIDById(int numId)
1841 {
1842 for ( int i = 0; i < XRCID_TABLE_SIZE; i++ )
1843 {
1844 for ( XRCID_record *rec = XRCID_Records[i]; rec; rec = rec->next )
1845 {
1846 if ( rec->id == numId )
1847 return wxString(rec->key);
1848 }
1849 }
1850
1851 return wxString();
1852 }
1853
1854 static void CleanXRCID_Record(XRCID_record *rec)
1855 {
1856 if (rec)
1857 {
1858 CleanXRCID_Record(rec->next);
1859
1860 free(rec->key);
1861 delete rec;
1862 }
1863 }
1864
1865 static void CleanXRCID_Records()
1866 {
1867 for (int i = 0; i < XRCID_TABLE_SIZE; i++)
1868 {
1869 CleanXRCID_Record(XRCID_Records[i]);
1870 XRCID_Records[i] = NULL;
1871 }
1872 }
1873
1874 static void AddStdXRCID_Records()
1875 {
1876 #define stdID(id) XRCID_Lookup(#id, id)
1877 stdID(-1);
1878
1879 stdID(wxID_ANY);
1880 stdID(wxID_SEPARATOR);
1881
1882 stdID(wxID_OPEN);
1883 stdID(wxID_CLOSE);
1884 stdID(wxID_NEW);
1885 stdID(wxID_SAVE);
1886 stdID(wxID_SAVEAS);
1887 stdID(wxID_REVERT);
1888 stdID(wxID_EXIT);
1889 stdID(wxID_UNDO);
1890 stdID(wxID_REDO);
1891 stdID(wxID_HELP);
1892 stdID(wxID_PRINT);
1893 stdID(wxID_PRINT_SETUP);
1894 stdID(wxID_PAGE_SETUP);
1895 stdID(wxID_PREVIEW);
1896 stdID(wxID_ABOUT);
1897 stdID(wxID_HELP_CONTENTS);
1898 stdID(wxID_HELP_COMMANDS);
1899 stdID(wxID_HELP_PROCEDURES);
1900 stdID(wxID_HELP_CONTEXT);
1901 stdID(wxID_CLOSE_ALL);
1902 stdID(wxID_PREFERENCES);
1903 stdID(wxID_EDIT);
1904 stdID(wxID_CUT);
1905 stdID(wxID_COPY);
1906 stdID(wxID_PASTE);
1907 stdID(wxID_CLEAR);
1908 stdID(wxID_FIND);
1909 stdID(wxID_DUPLICATE);
1910 stdID(wxID_SELECTALL);
1911 stdID(wxID_DELETE);
1912 stdID(wxID_REPLACE);
1913 stdID(wxID_REPLACE_ALL);
1914 stdID(wxID_PROPERTIES);
1915 stdID(wxID_VIEW_DETAILS);
1916 stdID(wxID_VIEW_LARGEICONS);
1917 stdID(wxID_VIEW_SMALLICONS);
1918 stdID(wxID_VIEW_LIST);
1919 stdID(wxID_VIEW_SORTDATE);
1920 stdID(wxID_VIEW_SORTNAME);
1921 stdID(wxID_VIEW_SORTSIZE);
1922 stdID(wxID_VIEW_SORTTYPE);
1923 stdID(wxID_FILE1);
1924 stdID(wxID_FILE2);
1925 stdID(wxID_FILE3);
1926 stdID(wxID_FILE4);
1927 stdID(wxID_FILE5);
1928 stdID(wxID_FILE6);
1929 stdID(wxID_FILE7);
1930 stdID(wxID_FILE8);
1931 stdID(wxID_FILE9);
1932 stdID(wxID_OK);
1933 stdID(wxID_CANCEL);
1934 stdID(wxID_APPLY);
1935 stdID(wxID_YES);
1936 stdID(wxID_NO);
1937 stdID(wxID_STATIC);
1938 stdID(wxID_FORWARD);
1939 stdID(wxID_BACKWARD);
1940 stdID(wxID_DEFAULT);
1941 stdID(wxID_MORE);
1942 stdID(wxID_SETUP);
1943 stdID(wxID_RESET);
1944 stdID(wxID_CONTEXT_HELP);
1945 stdID(wxID_YESTOALL);
1946 stdID(wxID_NOTOALL);
1947 stdID(wxID_ABORT);
1948 stdID(wxID_RETRY);
1949 stdID(wxID_IGNORE);
1950 stdID(wxID_ADD);
1951 stdID(wxID_REMOVE);
1952 stdID(wxID_UP);
1953 stdID(wxID_DOWN);
1954 stdID(wxID_HOME);
1955 stdID(wxID_REFRESH);
1956 stdID(wxID_STOP);
1957 stdID(wxID_INDEX);
1958 stdID(wxID_BOLD);
1959 stdID(wxID_ITALIC);
1960 stdID(wxID_JUSTIFY_CENTER);
1961 stdID(wxID_JUSTIFY_FILL);
1962 stdID(wxID_JUSTIFY_RIGHT);
1963 stdID(wxID_JUSTIFY_LEFT);
1964 stdID(wxID_UNDERLINE);
1965 stdID(wxID_INDENT);
1966 stdID(wxID_UNINDENT);
1967 stdID(wxID_ZOOM_100);
1968 stdID(wxID_ZOOM_FIT);
1969 stdID(wxID_ZOOM_IN);
1970 stdID(wxID_ZOOM_OUT);
1971 stdID(wxID_UNDELETE);
1972 stdID(wxID_REVERT_TO_SAVED);
1973 stdID(wxID_SYSTEM_MENU);
1974 stdID(wxID_CLOSE_FRAME);
1975 stdID(wxID_MOVE_FRAME);
1976 stdID(wxID_RESIZE_FRAME);
1977 stdID(wxID_MAXIMIZE_FRAME);
1978 stdID(wxID_ICONIZE_FRAME);
1979 stdID(wxID_RESTORE_FRAME);
1980 stdID(wxID_CDROM);
1981 stdID(wxID_CONVERT);
1982 stdID(wxID_EXECUTE);
1983 stdID(wxID_FLOPPY);
1984 stdID(wxID_HARDDISK);
1985 stdID(wxID_BOTTOM);
1986 stdID(wxID_FIRST);
1987 stdID(wxID_LAST);
1988 stdID(wxID_TOP);
1989 stdID(wxID_INFO);
1990 stdID(wxID_JUMP_TO);
1991 stdID(wxID_NETWORK);
1992 stdID(wxID_SELECT_COLOR);
1993 stdID(wxID_SELECT_FONT);
1994 stdID(wxID_SORT_ASCENDING);
1995 stdID(wxID_SORT_DESCENDING);
1996 stdID(wxID_SPELL_CHECK);
1997 stdID(wxID_STRIKETHROUGH);
1998
1999 #undef stdID
2000 }
2001
2002
2003
2004
2005
2006 //-----------------------------------------------------------------------------
2007 // module and globals
2008 //-----------------------------------------------------------------------------
2009
2010 // normally we would do the cleanup from wxXmlResourceModule::OnExit() but it
2011 // can happen that some XRC records have been created because of the use of
2012 // XRCID() in event tables, which happens during static objects initialization,
2013 // but then the application initialization failed and so the wx modules were
2014 // neither initialized nor cleaned up -- this static object does the cleanup in
2015 // this case
2016 static struct wxXRCStaticCleanup
2017 {
2018 ~wxXRCStaticCleanup() { CleanXRCID_Records(); }
2019 } s_staticCleanup;
2020
2021 class wxXmlResourceModule: public wxModule
2022 {
2023 DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
2024 public:
2025 wxXmlResourceModule() {}
2026 bool OnInit()
2027 {
2028 wxXmlResource::AddSubclassFactory(new wxXmlSubclassFactoryCXX);
2029 return true;
2030 }
2031 void OnExit()
2032 {
2033 delete wxXmlResource::Set(NULL);
2034 if(wxXmlResource::ms_subclassFactories)
2035 {
2036 for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
2037 i != wxXmlResource::ms_subclassFactories->end(); ++i )
2038 {
2039 delete *i;
2040 }
2041 wxDELETE(wxXmlResource::ms_subclassFactories);
2042 }
2043 CleanXRCID_Records();
2044 }
2045 };
2046
2047 IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)
2048
2049
2050 // When wxXml is loaded dynamically after the application is already running
2051 // then the built-in module system won't pick this one up. Add it manually.
2052 void wxXmlInitResourceModule()
2053 {
2054 wxModule* module = new wxXmlResourceModule;
2055 module->Init();
2056 wxModule::RegisterModule(module);
2057 }
2058
2059 #endif // wxUSE_XRC