set icons bundle, not single icon, for frames loaded from XRC
[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 namespace
1234 {
1235
1236 // if 'param' has stock_id/stock_client, extracts them and returns true
1237 bool GetStockArtAttrs(const wxXmlNode *paramNode,
1238 const wxString& defaultArtClient,
1239 wxString& art_id, wxString& art_client)
1240 {
1241 if ( paramNode )
1242 {
1243 art_id = paramNode->GetAttribute("stock_id", "");
1244
1245 if ( !art_id.empty() )
1246 {
1247 art_id = wxART_MAKE_ART_ID_FROM_STR(art_id);
1248
1249 art_client = paramNode->GetAttribute("stock_client", "");
1250 if ( art_client.empty() )
1251 art_client = defaultArtClient;
1252 else
1253 art_client = wxART_MAKE_CLIENT_ID_FROM_STR(art_client);
1254
1255 return true;
1256 }
1257 }
1258
1259 return false;
1260 }
1261
1262 } // anonymous namespace
1263
1264 wxBitmap wxXmlResourceHandler::GetBitmap(const wxString& param,
1265 const wxArtClient& defaultArtClient,
1266 wxSize size)
1267 {
1268 /* If the bitmap is specified as stock item, query wxArtProvider for it: */
1269 wxString art_id, art_client;
1270 if ( GetStockArtAttrs(GetParamNode(param), defaultArtClient,
1271 art_id, art_client) )
1272 {
1273 wxBitmap stockArt(wxArtProvider::GetBitmap(art_id, art_client, size));
1274 if ( stockArt.Ok() )
1275 return stockArt;
1276 }
1277
1278 /* ...or load the bitmap from file: */
1279 wxString name = GetParamValue(param);
1280 if (name.empty()) return wxNullBitmap;
1281 #if wxUSE_FILESYSTEM
1282 wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
1283 if (fsfile == NULL)
1284 {
1285 ReportParamError
1286 (
1287 param,
1288 wxString::Format("cannot open bitmap resource \"%s\"", name)
1289 );
1290 return wxNullBitmap;
1291 }
1292 wxImage img(*(fsfile->GetStream()));
1293 delete fsfile;
1294 #else
1295 wxImage img(name);
1296 #endif
1297
1298 if (!img.Ok())
1299 {
1300 ReportParamError
1301 (
1302 param,
1303 wxString::Format("cannot create bitmap from \"%s\"", name)
1304 );
1305 return wxNullBitmap;
1306 }
1307 if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
1308 return wxBitmap(img);
1309 }
1310
1311
1312 wxIcon wxXmlResourceHandler::GetIcon(const wxString& param,
1313 const wxArtClient& defaultArtClient,
1314 wxSize size)
1315 {
1316 wxIcon icon;
1317 icon.CopyFromBitmap(GetBitmap(param, defaultArtClient, size));
1318 return icon;
1319 }
1320
1321 wxIconBundle wxXmlResourceHandler::GetIconBundle(const wxString& param,
1322 const wxArtClient& defaultArtClient)
1323 {
1324 wxString art_id, art_client;
1325 if ( GetStockArtAttrs(GetParamNode(param), defaultArtClient,
1326 art_id, art_client) )
1327 {
1328 wxIconBundle stockArt(wxArtProvider::GetIconBundle(art_id, art_client));
1329 if ( stockArt.IsOk() )
1330 return stockArt;
1331 }
1332
1333 const wxString name = GetParamValue(param);
1334 if ( name.empty() )
1335 return wxNullIconBundle;
1336
1337 #if wxUSE_FILESYSTEM
1338 wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
1339 if ( fsfile == NULL )
1340 {
1341 ReportParamError
1342 (
1343 param,
1344 wxString::Format("cannot open icon resource \"%s\"", name)
1345 );
1346 return wxNullIconBundle;
1347 }
1348
1349 wxIconBundle bundle(*(fsfile->GetStream()));
1350 delete fsfile;
1351 #else
1352 wxIconBundle bundle(name);
1353 #endif
1354
1355 if ( !bundle.IsOk() )
1356 {
1357 ReportParamError
1358 (
1359 param,
1360 wxString::Format("cannot create icon from \"%s\"", name)
1361 );
1362 return wxNullIconBundle;
1363 }
1364
1365 return bundle;
1366 }
1367
1368
1369 wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
1370 {
1371 wxCHECK_MSG(m_node, NULL, wxT("You can't access handler data before it was initialized!"));
1372
1373 wxXmlNode *n = m_node->GetChildren();
1374
1375 while (n)
1376 {
1377 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
1378 {
1379 // TODO: check that there are no other properties/parameters with
1380 // the same name and log an error if there are (can't do this
1381 // right now as I'm not sure if it's not going to break code
1382 // using this function in unintentional way (i.e. for
1383 // accessing other things than properties), for example
1384 // wxBitmapComboBoxXmlHandler almost surely does
1385 return n;
1386 }
1387 n = n->GetNext();
1388 }
1389 return NULL;
1390 }
1391
1392 bool wxXmlResourceHandler::IsOfClass(wxXmlNode *node, const wxString& classname)
1393 {
1394 return node->GetAttribute(wxT("class"), wxEmptyString) == classname;
1395 }
1396
1397
1398
1399 wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
1400 {
1401 wxXmlNode *n = node;
1402 if (n == NULL) return wxEmptyString;
1403 n = n->GetChildren();
1404
1405 while (n)
1406 {
1407 if (n->GetType() == wxXML_TEXT_NODE ||
1408 n->GetType() == wxXML_CDATA_SECTION_NODE)
1409 return n->GetContent();
1410 n = n->GetNext();
1411 }
1412 return wxEmptyString;
1413 }
1414
1415
1416
1417 wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
1418 {
1419 if (param.empty())
1420 return GetNodeContent(m_node);
1421 else
1422 return GetNodeContent(GetParamNode(param));
1423 }
1424
1425
1426
1427 wxSize wxXmlResourceHandler::GetSize(const wxString& param,
1428 wxWindow *windowToUse)
1429 {
1430 wxString s = GetParamValue(param);
1431 if (s.empty()) s = wxT("-1,-1");
1432 bool is_dlg;
1433 long sx, sy = 0;
1434
1435 is_dlg = s[s.length()-1] == wxT('d');
1436 if (is_dlg) s.RemoveLast();
1437
1438 if (!s.BeforeFirst(wxT(',')).ToLong(&sx) ||
1439 !s.AfterLast(wxT(',')).ToLong(&sy))
1440 {
1441 ReportParamError
1442 (
1443 param,
1444 wxString::Format("cannot parse coordinates value \"%s\"", s)
1445 );
1446 return wxDefaultSize;
1447 }
1448
1449 if (is_dlg)
1450 {
1451 if (windowToUse)
1452 {
1453 return wxDLG_UNIT(windowToUse, wxSize(sx, sy));
1454 }
1455 else if (m_parentAsWindow)
1456 {
1457 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, sy));
1458 }
1459 else
1460 {
1461 ReportParamError
1462 (
1463 param,
1464 "cannot convert dialog units: dialog unknown"
1465 );
1466 return wxDefaultSize;
1467 }
1468 }
1469
1470 return wxSize(sx, sy);
1471 }
1472
1473
1474
1475 wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
1476 {
1477 wxSize sz = GetSize(param);
1478 return wxPoint(sz.x, sz.y);
1479 }
1480
1481
1482
1483 wxCoord wxXmlResourceHandler::GetDimension(const wxString& param,
1484 wxCoord defaultv,
1485 wxWindow *windowToUse)
1486 {
1487 wxString s = GetParamValue(param);
1488 if (s.empty()) return defaultv;
1489 bool is_dlg;
1490 long sx;
1491
1492 is_dlg = s[s.length()-1] == wxT('d');
1493 if (is_dlg) s.RemoveLast();
1494
1495 if (!s.ToLong(&sx))
1496 {
1497 ReportParamError
1498 (
1499 param,
1500 wxString::Format("cannot parse dimension value \"%s\"", s)
1501 );
1502 return defaultv;
1503 }
1504
1505 if (is_dlg)
1506 {
1507 if (windowToUse)
1508 {
1509 return wxDLG_UNIT(windowToUse, wxSize(sx, 0)).x;
1510 }
1511 else if (m_parentAsWindow)
1512 {
1513 return wxDLG_UNIT(m_parentAsWindow, wxSize(sx, 0)).x;
1514 }
1515 else
1516 {
1517 ReportParamError
1518 (
1519 param,
1520 "cannot convert dialog units: dialog unknown"
1521 );
1522 return defaultv;
1523 }
1524 }
1525
1526 return sx;
1527 }
1528
1529
1530 // Get system font index using indexname
1531 static wxFont GetSystemFont(const wxString& name)
1532 {
1533 if (!name.empty())
1534 {
1535 #define SYSFNT(fnt) \
1536 if (name == _T(#fnt)) return wxSystemSettings::GetFont(fnt);
1537 SYSFNT(wxSYS_OEM_FIXED_FONT)
1538 SYSFNT(wxSYS_ANSI_FIXED_FONT)
1539 SYSFNT(wxSYS_ANSI_VAR_FONT)
1540 SYSFNT(wxSYS_SYSTEM_FONT)
1541 SYSFNT(wxSYS_DEVICE_DEFAULT_FONT)
1542 SYSFNT(wxSYS_SYSTEM_FIXED_FONT)
1543 SYSFNT(wxSYS_DEFAULT_GUI_FONT)
1544 #undef SYSFNT
1545 }
1546
1547 return wxNullFont;
1548 }
1549
1550 wxFont wxXmlResourceHandler::GetFont(const wxString& param)
1551 {
1552 wxXmlNode *font_node = GetParamNode(param);
1553 if (font_node == NULL)
1554 {
1555 ReportError(
1556 wxString::Format("cannot find font node \"%s\"", param));
1557 return wxNullFont;
1558 }
1559
1560 wxXmlNode *oldnode = m_node;
1561 m_node = font_node;
1562
1563 // font attributes:
1564
1565 // size
1566 int isize = -1;
1567 bool hasSize = HasParam(wxT("size"));
1568 if (hasSize)
1569 isize = GetLong(wxT("size"), -1);
1570
1571 // style
1572 int istyle = wxNORMAL;
1573 bool hasStyle = HasParam(wxT("style"));
1574 if (hasStyle)
1575 {
1576 wxString style = GetParamValue(wxT("style"));
1577 if (style == wxT("italic"))
1578 istyle = wxITALIC;
1579 else if (style == wxT("slant"))
1580 istyle = wxSLANT;
1581 }
1582
1583 // weight
1584 int iweight = wxNORMAL;
1585 bool hasWeight = HasParam(wxT("weight"));
1586 if (hasWeight)
1587 {
1588 wxString weight = GetParamValue(wxT("weight"));
1589 if (weight == wxT("bold"))
1590 iweight = wxBOLD;
1591 else if (weight == wxT("light"))
1592 iweight = wxLIGHT;
1593 }
1594
1595 // underline
1596 bool hasUnderlined = HasParam(wxT("underlined"));
1597 bool underlined = hasUnderlined ? GetBool(wxT("underlined"), false) : false;
1598
1599 // family and facename
1600 int ifamily = wxDEFAULT;
1601 bool hasFamily = HasParam(wxT("family"));
1602 if (hasFamily)
1603 {
1604 wxString family = GetParamValue(wxT("family"));
1605 if (family == wxT("decorative")) ifamily = wxDECORATIVE;
1606 else if (family == wxT("roman")) ifamily = wxROMAN;
1607 else if (family == wxT("script")) ifamily = wxSCRIPT;
1608 else if (family == wxT("swiss")) ifamily = wxSWISS;
1609 else if (family == wxT("modern")) ifamily = wxMODERN;
1610 else if (family == wxT("teletype")) ifamily = wxTELETYPE;
1611 }
1612
1613
1614 wxString facename;
1615 bool hasFacename = HasParam(wxT("face"));
1616 if (hasFacename)
1617 {
1618 wxString faces = GetParamValue(wxT("face"));
1619 wxStringTokenizer tk(faces, wxT(","));
1620 #if wxUSE_FONTENUM
1621 wxArrayString facenames(wxFontEnumerator::GetFacenames());
1622 while (tk.HasMoreTokens())
1623 {
1624 int index = facenames.Index(tk.GetNextToken(), false);
1625 if (index != wxNOT_FOUND)
1626 {
1627 facename = facenames[index];
1628 break;
1629 }
1630 }
1631 #else // !wxUSE_FONTENUM
1632 // just use the first face name if we can't check its availability:
1633 if (tk.HasMoreTokens())
1634 facename = tk.GetNextToken();
1635 #endif // wxUSE_FONTENUM/!wxUSE_FONTENUM
1636 }
1637
1638 // encoding
1639 wxFontEncoding enc = wxFONTENCODING_DEFAULT;
1640 bool hasEncoding = HasParam(wxT("encoding"));
1641 if (hasEncoding)
1642 {
1643 wxString encoding = GetParamValue(wxT("encoding"));
1644 wxFontMapper mapper;
1645 if (!encoding.empty())
1646 enc = mapper.CharsetToEncoding(encoding);
1647 if (enc == wxFONTENCODING_SYSTEM)
1648 enc = wxFONTENCODING_DEFAULT;
1649 }
1650
1651 // is this font based on a system font?
1652 wxFont font = GetSystemFont(GetParamValue(wxT("sysfont")));
1653
1654 if (font.Ok())
1655 {
1656 if (hasSize && isize != -1)
1657 font.SetPointSize(isize);
1658 else if (HasParam(wxT("relativesize")))
1659 font.SetPointSize(int(font.GetPointSize() *
1660 GetFloat(wxT("relativesize"))));
1661
1662 if (hasStyle)
1663 font.SetStyle(istyle);
1664 if (hasWeight)
1665 font.SetWeight(iweight);
1666 if (hasUnderlined)
1667 font.SetUnderlined(underlined);
1668 if (hasFamily)
1669 font.SetFamily(ifamily);
1670 if (hasFacename)
1671 font.SetFaceName(facename);
1672 if (hasEncoding)
1673 font.SetDefaultEncoding(enc);
1674 }
1675 else // not based on system font
1676 {
1677 font = wxFont(isize == -1 ? wxNORMAL_FONT->GetPointSize() : isize,
1678 ifamily, istyle, iweight,
1679 underlined, facename, enc);
1680 }
1681
1682 m_node = oldnode;
1683 return font;
1684 }
1685
1686
1687 void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
1688 {
1689 //FIXME : add cursor
1690
1691 if (HasParam(wxT("exstyle")))
1692 // Have to OR it with existing style, since
1693 // some implementations (e.g. wxGTK) use the extra style
1694 // during creation
1695 wnd->SetExtraStyle(wnd->GetExtraStyle() | GetStyle(wxT("exstyle")));
1696 if (HasParam(wxT("bg")))
1697 wnd->SetBackgroundColour(GetColour(wxT("bg")));
1698 if (HasParam(wxT("fg")))
1699 wnd->SetForegroundColour(GetColour(wxT("fg")));
1700 if (GetBool(wxT("enabled"), 1) == 0)
1701 wnd->Enable(false);
1702 if (GetBool(wxT("focused"), 0) == 1)
1703 wnd->SetFocus();
1704 if (GetBool(wxT("hidden"), 0) == 1)
1705 wnd->Show(false);
1706 #if wxUSE_TOOLTIPS
1707 if (HasParam(wxT("tooltip")))
1708 wnd->SetToolTip(GetText(wxT("tooltip")));
1709 #endif
1710 if (HasParam(wxT("font")))
1711 wnd->SetFont(GetFont());
1712 if (HasParam(wxT("help")))
1713 wnd->SetHelpText(GetText(wxT("help")));
1714 }
1715
1716
1717 void wxXmlResourceHandler::CreateChildren(wxObject *parent, bool this_hnd_only)
1718 {
1719 for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() )
1720 {
1721 if ( IsObjectNode(n) )
1722 {
1723 m_resource->CreateResFromNode(n, parent, NULL,
1724 this_hnd_only ? this : NULL);
1725 }
1726 }
1727 }
1728
1729
1730 void wxXmlResourceHandler::CreateChildrenPrivately(wxObject *parent, wxXmlNode *rootnode)
1731 {
1732 wxXmlNode *root;
1733 if (rootnode == NULL) root = m_node; else root = rootnode;
1734 wxXmlNode *n = root->GetChildren();
1735
1736 while (n)
1737 {
1738 if (n->GetType() == wxXML_ELEMENT_NODE && CanHandle(n))
1739 {
1740 CreateResource(n, parent, NULL);
1741 }
1742 n = n->GetNext();
1743 }
1744 }
1745
1746
1747 //-----------------------------------------------------------------------------
1748 // errors reporting
1749 //-----------------------------------------------------------------------------
1750
1751 void wxXmlResourceHandler::ReportError(const wxString& message)
1752 {
1753 m_resource->ReportError(m_node, message);
1754 }
1755
1756 void wxXmlResourceHandler::ReportError(wxXmlNode *context,
1757 const wxString& message)
1758 {
1759 m_resource->ReportError(context ? context : m_node, message);
1760 }
1761
1762 void wxXmlResourceHandler::ReportParamError(const wxString& param,
1763 const wxString& message)
1764 {
1765 m_resource->ReportError(GetParamNode(param), message);
1766 }
1767
1768 namespace
1769 {
1770
1771 wxString
1772 GetFileNameFromNode(wxXmlNode *node, const wxXmlResourceDataRecords& files)
1773 {
1774 wxXmlNode *root = node;
1775 while ( root->GetParent() )
1776 root = root->GetParent();
1777
1778 for ( wxXmlResourceDataRecords::const_iterator i = files.begin();
1779 i != files.end(); ++i )
1780 {
1781 if ( (*i)->Doc->GetRoot() == root )
1782 {
1783 return (*i)->File;
1784 }
1785 }
1786
1787 return wxEmptyString; // not found
1788 }
1789
1790 } // anonymous namespace
1791
1792 void wxXmlResource::ReportError(wxXmlNode *context, const wxString& message)
1793 {
1794 if ( !context )
1795 {
1796 DoReportError("", NULL, message);
1797 return;
1798 }
1799
1800 // We need to find out the file that 'context' is part of. Performance of
1801 // this code is not critical, so we simply find the root XML node and
1802 // compare it with all loaded XRC files.
1803 const wxString filename = GetFileNameFromNode(context, Data());
1804
1805 DoReportError(filename, context, message);
1806 }
1807
1808 void wxXmlResource::DoReportError(const wxString& xrcFile, wxXmlNode *position,
1809 const wxString& message)
1810 {
1811 const int line = position ? position->GetLineNumber() : -1;
1812
1813 wxString loc;
1814 if ( !xrcFile.empty() )
1815 loc = xrcFile + ':';
1816 if ( line != -1 )
1817 loc += wxString::Format("%d:", line);
1818 if ( !loc.empty() )
1819 loc += ' ';
1820
1821 wxLogError("XRC error: %s%s", loc, message);
1822 }
1823
1824
1825 //-----------------------------------------------------------------------------
1826 // XRCID implementation
1827 //-----------------------------------------------------------------------------
1828
1829 #define XRCID_TABLE_SIZE 1024
1830
1831
1832 struct XRCID_record
1833 {
1834 /* Hold the id so that once an id is allocated for a name, it
1835 does not get created again by NewControlId at least
1836 until we are done with it */
1837 wxWindowIDRef id;
1838 char *key;
1839 XRCID_record *next;
1840 };
1841
1842 static XRCID_record *XRCID_Records[XRCID_TABLE_SIZE] = {NULL};
1843
1844 static int XRCID_Lookup(const char *str_id, int value_if_not_found = wxID_NONE)
1845 {
1846 int index = 0;
1847
1848 for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
1849 index %= XRCID_TABLE_SIZE;
1850
1851 XRCID_record *oldrec = NULL;
1852 for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
1853 {
1854 if (wxStrcmp(rec->key, str_id) == 0)
1855 {
1856 return rec->id;
1857 }
1858 oldrec = rec;
1859 }
1860
1861 XRCID_record **rec_var = (oldrec == NULL) ?
1862 &XRCID_Records[index] : &oldrec->next;
1863 *rec_var = new XRCID_record;
1864 (*rec_var)->key = wxStrdup(str_id);
1865 (*rec_var)->next = NULL;
1866
1867 char *end;
1868 if (value_if_not_found != wxID_NONE)
1869 (*rec_var)->id = value_if_not_found;
1870 else
1871 {
1872 int asint = wxStrtol(str_id, &end, 10);
1873 if (*str_id && *end == 0)
1874 {
1875 // if str_id was integer, keep it verbosely:
1876 (*rec_var)->id = asint;
1877 }
1878 else
1879 {
1880 (*rec_var)->id = wxWindowBase::NewControlId();
1881 }
1882 }
1883
1884 return (*rec_var)->id;
1885 }
1886
1887 static void AddStdXRCID_Records();
1888
1889 /*static*/
1890 int wxXmlResource::DoGetXRCID(const char *str_id, int value_if_not_found)
1891 {
1892 static bool s_stdIDsAdded = false;
1893
1894 if ( !s_stdIDsAdded )
1895 {
1896 s_stdIDsAdded = true;
1897 AddStdXRCID_Records();
1898 }
1899
1900 return XRCID_Lookup(str_id, value_if_not_found);
1901 }
1902
1903 /* static */
1904 wxString wxXmlResource::FindXRCIDById(int numId)
1905 {
1906 for ( int i = 0; i < XRCID_TABLE_SIZE; i++ )
1907 {
1908 for ( XRCID_record *rec = XRCID_Records[i]; rec; rec = rec->next )
1909 {
1910 if ( rec->id == numId )
1911 return wxString(rec->key);
1912 }
1913 }
1914
1915 return wxString();
1916 }
1917
1918 static void CleanXRCID_Record(XRCID_record *rec)
1919 {
1920 if (rec)
1921 {
1922 CleanXRCID_Record(rec->next);
1923
1924 free(rec->key);
1925 delete rec;
1926 }
1927 }
1928
1929 static void CleanXRCID_Records()
1930 {
1931 for (int i = 0; i < XRCID_TABLE_SIZE; i++)
1932 {
1933 CleanXRCID_Record(XRCID_Records[i]);
1934 XRCID_Records[i] = NULL;
1935 }
1936 }
1937
1938 static void AddStdXRCID_Records()
1939 {
1940 #define stdID(id) XRCID_Lookup(#id, id)
1941 stdID(-1);
1942
1943 stdID(wxID_ANY);
1944 stdID(wxID_SEPARATOR);
1945
1946 stdID(wxID_OPEN);
1947 stdID(wxID_CLOSE);
1948 stdID(wxID_NEW);
1949 stdID(wxID_SAVE);
1950 stdID(wxID_SAVEAS);
1951 stdID(wxID_REVERT);
1952 stdID(wxID_EXIT);
1953 stdID(wxID_UNDO);
1954 stdID(wxID_REDO);
1955 stdID(wxID_HELP);
1956 stdID(wxID_PRINT);
1957 stdID(wxID_PRINT_SETUP);
1958 stdID(wxID_PAGE_SETUP);
1959 stdID(wxID_PREVIEW);
1960 stdID(wxID_ABOUT);
1961 stdID(wxID_HELP_CONTENTS);
1962 stdID(wxID_HELP_COMMANDS);
1963 stdID(wxID_HELP_PROCEDURES);
1964 stdID(wxID_HELP_CONTEXT);
1965 stdID(wxID_CLOSE_ALL);
1966 stdID(wxID_PREFERENCES);
1967 stdID(wxID_EDIT);
1968 stdID(wxID_CUT);
1969 stdID(wxID_COPY);
1970 stdID(wxID_PASTE);
1971 stdID(wxID_CLEAR);
1972 stdID(wxID_FIND);
1973 stdID(wxID_DUPLICATE);
1974 stdID(wxID_SELECTALL);
1975 stdID(wxID_DELETE);
1976 stdID(wxID_REPLACE);
1977 stdID(wxID_REPLACE_ALL);
1978 stdID(wxID_PROPERTIES);
1979 stdID(wxID_VIEW_DETAILS);
1980 stdID(wxID_VIEW_LARGEICONS);
1981 stdID(wxID_VIEW_SMALLICONS);
1982 stdID(wxID_VIEW_LIST);
1983 stdID(wxID_VIEW_SORTDATE);
1984 stdID(wxID_VIEW_SORTNAME);
1985 stdID(wxID_VIEW_SORTSIZE);
1986 stdID(wxID_VIEW_SORTTYPE);
1987 stdID(wxID_FILE1);
1988 stdID(wxID_FILE2);
1989 stdID(wxID_FILE3);
1990 stdID(wxID_FILE4);
1991 stdID(wxID_FILE5);
1992 stdID(wxID_FILE6);
1993 stdID(wxID_FILE7);
1994 stdID(wxID_FILE8);
1995 stdID(wxID_FILE9);
1996 stdID(wxID_OK);
1997 stdID(wxID_CANCEL);
1998 stdID(wxID_APPLY);
1999 stdID(wxID_YES);
2000 stdID(wxID_NO);
2001 stdID(wxID_STATIC);
2002 stdID(wxID_FORWARD);
2003 stdID(wxID_BACKWARD);
2004 stdID(wxID_DEFAULT);
2005 stdID(wxID_MORE);
2006 stdID(wxID_SETUP);
2007 stdID(wxID_RESET);
2008 stdID(wxID_CONTEXT_HELP);
2009 stdID(wxID_YESTOALL);
2010 stdID(wxID_NOTOALL);
2011 stdID(wxID_ABORT);
2012 stdID(wxID_RETRY);
2013 stdID(wxID_IGNORE);
2014 stdID(wxID_ADD);
2015 stdID(wxID_REMOVE);
2016 stdID(wxID_UP);
2017 stdID(wxID_DOWN);
2018 stdID(wxID_HOME);
2019 stdID(wxID_REFRESH);
2020 stdID(wxID_STOP);
2021 stdID(wxID_INDEX);
2022 stdID(wxID_BOLD);
2023 stdID(wxID_ITALIC);
2024 stdID(wxID_JUSTIFY_CENTER);
2025 stdID(wxID_JUSTIFY_FILL);
2026 stdID(wxID_JUSTIFY_RIGHT);
2027 stdID(wxID_JUSTIFY_LEFT);
2028 stdID(wxID_UNDERLINE);
2029 stdID(wxID_INDENT);
2030 stdID(wxID_UNINDENT);
2031 stdID(wxID_ZOOM_100);
2032 stdID(wxID_ZOOM_FIT);
2033 stdID(wxID_ZOOM_IN);
2034 stdID(wxID_ZOOM_OUT);
2035 stdID(wxID_UNDELETE);
2036 stdID(wxID_REVERT_TO_SAVED);
2037 stdID(wxID_SYSTEM_MENU);
2038 stdID(wxID_CLOSE_FRAME);
2039 stdID(wxID_MOVE_FRAME);
2040 stdID(wxID_RESIZE_FRAME);
2041 stdID(wxID_MAXIMIZE_FRAME);
2042 stdID(wxID_ICONIZE_FRAME);
2043 stdID(wxID_RESTORE_FRAME);
2044 stdID(wxID_CDROM);
2045 stdID(wxID_CONVERT);
2046 stdID(wxID_EXECUTE);
2047 stdID(wxID_FLOPPY);
2048 stdID(wxID_HARDDISK);
2049 stdID(wxID_BOTTOM);
2050 stdID(wxID_FIRST);
2051 stdID(wxID_LAST);
2052 stdID(wxID_TOP);
2053 stdID(wxID_INFO);
2054 stdID(wxID_JUMP_TO);
2055 stdID(wxID_NETWORK);
2056 stdID(wxID_SELECT_COLOR);
2057 stdID(wxID_SELECT_FONT);
2058 stdID(wxID_SORT_ASCENDING);
2059 stdID(wxID_SORT_DESCENDING);
2060 stdID(wxID_SPELL_CHECK);
2061 stdID(wxID_STRIKETHROUGH);
2062
2063 #undef stdID
2064 }
2065
2066
2067
2068
2069
2070 //-----------------------------------------------------------------------------
2071 // module and globals
2072 //-----------------------------------------------------------------------------
2073
2074 // normally we would do the cleanup from wxXmlResourceModule::OnExit() but it
2075 // can happen that some XRC records have been created because of the use of
2076 // XRCID() in event tables, which happens during static objects initialization,
2077 // but then the application initialization failed and so the wx modules were
2078 // neither initialized nor cleaned up -- this static object does the cleanup in
2079 // this case
2080 static struct wxXRCStaticCleanup
2081 {
2082 ~wxXRCStaticCleanup() { CleanXRCID_Records(); }
2083 } s_staticCleanup;
2084
2085 class wxXmlResourceModule: public wxModule
2086 {
2087 DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
2088 public:
2089 wxXmlResourceModule() {}
2090 bool OnInit()
2091 {
2092 wxXmlResource::AddSubclassFactory(new wxXmlSubclassFactoryCXX);
2093 return true;
2094 }
2095 void OnExit()
2096 {
2097 delete wxXmlResource::Set(NULL);
2098 if(wxXmlResource::ms_subclassFactories)
2099 {
2100 for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
2101 i != wxXmlResource::ms_subclassFactories->end(); ++i )
2102 {
2103 delete *i;
2104 }
2105 wxDELETE(wxXmlResource::ms_subclassFactories);
2106 }
2107 CleanXRCID_Records();
2108 }
2109 };
2110
2111 IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)
2112
2113
2114 // When wxXml is loaded dynamically after the application is already running
2115 // then the built-in module system won't pick this one up. Add it manually.
2116 void wxXmlInitResourceModule()
2117 {
2118 wxModule* module = new wxXmlResourceModule;
2119 module->Init();
2120 wxModule::RegisterModule(module);
2121 }
2122
2123 #endif // wxUSE_XRC