]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/xml/xmlres.cpp
0318204747cb2bf9c7b40e4652652819f07b5222
[wxWidgets.git] / contrib / src / xml / xmlres.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: xmlres.cpp
3 // Purpose: XML 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 #ifdef __GNUG__
12 #pragma implementation "xmlres.h"
13 #endif
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #include "wx/dialog.h"
23 #include "wx/panel.h"
24 #include "wx/wfstream.h"
25 #include "wx/filesys.h"
26 #include "wx/log.h"
27 #include "wx/intl.h"
28 #include "wx/tokenzr.h"
29 #include "wx/module.h"
30
31 #include "wx/xml/xml.h"
32 #include "wx/xml/xmlres.h"
33
34 #include "wx/arrimpl.cpp"
35 WX_DEFINE_OBJARRAY(wxXmlResourceDataRecords);
36
37
38 wxXmlResource::wxXmlResource()
39 {
40 m_Handlers.DeleteContents(TRUE);
41 }
42
43 wxXmlResource::wxXmlResource(const wxString& filemask, int type)
44 {
45 m_Handlers.DeleteContents(TRUE);
46 Load(filemask, type);
47 }
48
49 wxXmlResource::~wxXmlResource()
50 {
51 ClearHandlers();
52 }
53
54
55 bool wxXmlResource::Load(const wxString& filemask, int type)
56 {
57 wxString fnd;
58 wxXmlResourceDataRecord *drec;
59
60 #if wxUSE_FILESYSTEM
61 wxFileSystem fsys;
62 # define wxXmlFindFirst fsys.FindFirst(filemask, wxFILE)
63 # define wxXmlFindNext fsys.FindNext()
64 #else
65 # define wxXmlFindFirst wxFindFirstFile(filemask, wxFILE)
66 # define wxXmlFindNext wxFindNextFile()
67 wxASSERT_MSG(type != wxXML_ARCHIVE, wxT("ZIP archive XML resources supported only with wxUSE_FILESYSTEM set to 1!"));
68 #endif
69 fnd = wxXmlFindFirst;
70 while (!!fnd)
71 {
72 #if wxUSE_FILESYSTEM
73 if (type == wxXML_ARCHIVE)
74 {
75 wxFileSystem fs2;
76 wxString fnd2;
77
78 fnd2 = fs2.FindFirst(fnd + wxT("#zip:*.xmb"), wxFILE);
79 while (!!fnd2)
80 {
81 drec = new wxXmlResourceDataRecord;
82 drec->File = fnd2;
83 m_Data.Add(drec);
84 fnd2 = fs2.FindNext();
85 }
86 }
87 else
88 #endif
89 {
90 drec = new wxXmlResourceDataRecord;
91 drec->File = fnd;
92 m_Data.Add(drec);
93 }
94 fnd = wxXmlFindNext;
95 }
96 # undef wxXmlFindFirst
97 # undef wxXmlFindNext
98 return TRUE;
99 }
100
101
102
103 void wxXmlResource::AddHandler(wxXmlResourceHandler *handler)
104 {
105 m_Handlers.Append(handler);
106 handler->SetParentResource(this);
107 }
108
109
110
111 void wxXmlResource::ClearHandlers()
112 {
113 m_Handlers.Clear();
114 }
115
116
117
118 wxMenu *wxXmlResource::LoadMenu(const wxString& name)
119 {
120 return (wxMenu*)CreateResFromNode(FindResource(name, wxT("menu")), NULL, NULL);
121 }
122
123
124
125 wxMenuBar *wxXmlResource::LoadMenuBar(const wxString& name)
126 {
127 return (wxMenuBar*)CreateResFromNode(FindResource(name, wxT("menubar")), NULL, NULL);
128 }
129
130
131
132 wxDialog *wxXmlResource::LoadDialog(wxWindow *parent, const wxString& name)
133 {
134 wxDialog *dialog = new wxDialog;
135 if (!LoadDialog(dialog, parent, name))
136 { delete dialog; return NULL; }
137 else return dialog;
138 }
139
140 bool wxXmlResource::LoadDialog(wxDialog *dlg, wxWindow *parent, const wxString& name)
141 {
142 return CreateResFromNode(FindResource(name, wxT("dialog")), parent, dlg) != NULL;
143 }
144
145
146
147 wxPanel *wxXmlResource::LoadPanel(wxWindow *parent, const wxString& name)
148 {
149 wxPanel *panel = new wxPanel;
150 if (!LoadPanel(panel, parent, name))
151 { delete panel; return NULL; }
152 else return panel;
153 }
154
155 bool wxXmlResource::LoadPanel(wxPanel *panel, wxWindow *parent, const wxString& name)
156 {
157 return CreateResFromNode(FindResource(name, wxT("panel")), parent, panel) != NULL;
158 }
159
160
161
162 void wxXmlResource::ProcessPlatformProperty(wxXmlNode *node)
163 {
164 wxString s;
165 bool isok;
166
167 wxXmlNode *c = node->GetChildren();
168 while (c)
169 {
170 isok = FALSE;
171 if (!c->GetPropVal(_T("platform"), &s))
172 isok = TRUE;
173 else
174 {
175 wxStringTokenizer tkn(s, " |");
176
177 while (tkn.HasMoreTokens())
178 {
179 s = tkn.GetNextToken();
180 if (
181 #ifdef __WXMSW__
182 s == wxString(_T("win"))
183 #elif defined(__UNIX__)
184 s == wxString(_T("unix"))
185 #elif defined(__MAC__)
186 s == wxString(_T("mac"))
187 #elif defined(__OS2__)
188 s == wxString(_T("os2"))
189 #else
190 FALSE
191 #endif
192 ) isok = TRUE;
193 }
194 }
195
196 if (isok)
197 ProcessPlatformProperty(c);
198 else
199 {
200 node->RemoveChild(c);
201 delete c;
202 }
203
204 c = c->GetNext();
205 }
206 }
207
208
209
210 void wxXmlResource::UpdateResources()
211 {
212 bool modif;
213 # if wxUSE_FILESYSTEM
214 wxFSFile *file;
215 wxFileSystem fsys;
216 # endif
217
218 for (size_t i = 0; i < m_Data.GetCount(); i++)
219 {
220 modif = (m_Data[i].Doc == NULL);
221
222 if (!modif)
223 {
224 # if wxUSE_FILESYSTEM
225 file = fsys.OpenFile(m_Data[i].File);
226 modif = file && file->GetModificationTime() > m_Data[i].Time;
227 if (!file)
228 wxLogError(_("Cannot open file '%s'."), m_Data[i].File.c_str());
229 delete file;
230 # else
231 modif = wxDateTime(wxFileModificationTime(m_Data[i].File)) > m_Data[i].Time;
232 # endif
233 }
234
235 if (modif)
236 {
237 wxInputStream *stream;
238
239 # if wxUSE_FILESYSTEM
240 file = fsys.OpenFile(m_Data[i].File);
241 stream = file->GetStream();
242 # else
243 stream = new wxFileInputStream(m_Data[i].File);
244 # endif
245
246 if (stream)
247 {
248 delete m_Data[i].Doc;
249 m_Data[i].Doc = new wxXmlDocument;
250 }
251 if (!stream || !m_Data[i].Doc->Load(*stream))
252 wxLogError(_("Cannot load resources from file '%s'."), m_Data[i].File.c_str());
253
254 if (m_Data[i].Doc->GetRoot()->GetName() != _T("resource"))
255 wxLogError(_("Invalid XML resource '%s': doesn't have root node 'resource'."), m_Data[i].File.c_str());
256
257 ProcessPlatformProperty(m_Data[i].Doc->GetRoot());
258
259 # if wxUSE_FILESYSTEM
260 delete file;
261 # else
262 delete stream;
263 # endif
264 }
265 }
266 }
267
268
269
270 wxXmlNode *wxXmlResource::FindResource(const wxString& name, const wxString& type)
271 {
272 UpdateResources(); //ensure everything is up-to-date
273
274 wxString dummy;
275 for (size_t f = 0; f < m_Data.GetCount(); f++)
276 {
277 for (wxXmlNode *node = m_Data[f].Doc->GetRoot()->GetChildren();
278 node; node = node->GetNext())
279 if ( node->GetType() == wxXML_ELEMENT_NODE &&
280 (!type || node->GetName() == type) &&
281 node->GetPropVal(wxT("name"), &dummy) &&
282 dummy == name)
283 return node;
284 }
285
286 wxLogError(_("XML resource '%s' (type '%s') not found!"),
287 name.c_str(), type.c_str());
288 return NULL;
289 }
290
291
292
293 wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, wxObject *instance)
294 {
295 if (node == NULL) return NULL;
296
297 wxXmlResourceHandler *handler;
298 wxObject *ret;
299 wxNode * ND = m_Handlers.GetFirst();
300 while (ND)
301 {
302 handler = (wxXmlResourceHandler*)ND->GetData();
303 if (handler->CanHandle(node))
304 {
305 ret = handler->CreateResource(node, parent, instance);
306 if (ret) return ret;
307 }
308 ND = ND->GetNext();
309 }
310
311 wxLogError(_("No handler found for XML node '%s'!"), node->GetName().c_str());
312 return NULL;
313 }
314
315
316
317
318
319
320
321
322
323 wxXmlResourceHandler::wxXmlResourceHandler()
324 : m_Node(NULL), m_Parent(NULL), m_Instance(NULL),
325 m_ParentAsWindow(NULL), m_InstanceAsWindow(NULL)
326 {}
327
328
329
330 wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance)
331 {
332 wxXmlNode *myNode = m_Node;
333 wxObject *myParent = m_Parent, *myInstance = m_Instance;
334 wxWindow *myParentAW = m_ParentAsWindow, *myInstanceAW = m_InstanceAsWindow;
335
336 m_Node = node;
337 m_Parent = parent;
338 m_Instance = instance;
339 m_ParentAsWindow = wxDynamicCast(m_Parent, wxWindow);
340 m_InstanceAsWindow = wxDynamicCast(m_Instance, wxWindow);
341
342 wxObject *returned = DoCreateResource();
343
344 m_Node = myNode;
345 m_Parent = myParent; m_ParentAsWindow = myParentAW;
346 m_Instance = myInstance; m_InstanceAsWindow = myInstanceAW;
347
348 return returned;
349 }
350
351
352 void wxXmlResourceHandler::AddStyle(const wxString& name, int value)
353 {
354 m_StyleNames.Add(name);
355 m_StyleValues.Add(value);
356 }
357
358
359 bool wxXmlResourceHandler::HasParam(const wxString& param)
360 {
361 return (GetParamNode(param) != NULL);
362 }
363
364
365 int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
366 {
367 wxString s = GetParamValue(param);
368
369 if (!s) return defaults;
370
371 wxStringTokenizer tkn(s, _T("| "), wxTOKEN_STRTOK);
372 int style = 0;
373 int index;
374 wxString fl;
375 while (tkn.HasMoreTokens())
376 {
377 fl = tkn.GetNextToken();
378 index = m_StyleNames.Index(fl);
379 if (index != wxNOT_FOUND)
380 style |= m_StyleValues[index];
381 else
382 wxLogError(_("Unknown style flag ") + fl);
383 }
384 return style;
385 }
386
387
388
389 wxString wxXmlResourceHandler::GetText(const wxString& param)
390 {
391 wxString str1 = GetParamValue(param);
392 wxString str2;
393 const wxChar *dt;
394
395 for (dt = str1.c_str(); *dt; dt++)
396 {
397 // Remap $ to &, map $$ to $ (for things like "&File..." --
398 // this is illegal in XML, so we use "$File..."):
399 if (*dt == '$')
400 switch (*(++dt))
401 {
402 case '$' : str2 << '$'; break;
403 default : str2 << '&' << *dt; break;
404 }
405 // Remap \n to CR, \r LF, \t to TAB:
406 else if (*dt == '\\')
407 switch (*(++dt))
408 {
409 case 'n' : str2 << '\n'; break;
410 case 't' : str2 << '\t'; break;
411 case 'r' : str2 << '\r'; break;
412 default : str2 << '\\' << *dt; break;
413 }
414 else str2 << *dt;
415 }
416 return str2;
417 }
418
419
420
421 long wxXmlResourceHandler::GetLong(const wxString& param, long defaultv)
422 {
423 long value;
424 wxString str1 = GetParamValue(param);
425
426 if (!str1.ToLong(&value))
427 value = defaultv;
428
429 return value;
430 }
431
432
433 int wxXmlResourceHandler::GetID()
434 {
435 wxString sid = GetName();
436 long num;
437
438 if (sid == _T("-1")) return -1;
439 else if (sid.IsNumber() && sid.ToLong(&num)) return num;
440 #define stdID(id) else if (sid == _T(#id)) return id
441 stdID(wxID_OPEN); stdID(wxID_CLOSE); stdID(wxID_NEW);
442 stdID(wxID_SAVE); stdID(wxID_SAVEAS); stdID(wxID_REVERT);
443 stdID(wxID_EXIT); stdID(wxID_UNDO); stdID(wxID_REDO);
444 stdID(wxID_HELP); stdID(wxID_PRINT); stdID(wxID_PRINT_SETUP);
445 stdID(wxID_PREVIEW); stdID(wxID_ABOUT); stdID(wxID_HELP_CONTENTS);
446 stdID(wxID_HELP_COMMANDS); stdID(wxID_HELP_PROCEDURES);
447 stdID(wxID_CUT); stdID(wxID_COPY); stdID(wxID_PASTE);
448 stdID(wxID_CLEAR); stdID(wxID_FIND); stdID(wxID_DUPLICATE);
449 stdID(wxID_SELECTALL); stdID(wxID_OK); stdID(wxID_CANCEL);
450 stdID(wxID_APPLY); stdID(wxID_YES); stdID(wxID_NO);
451 stdID(wxID_STATIC); stdID(wxID_FORWARD); stdID(wxID_BACKWARD);
452 stdID(wxID_DEFAULT); stdID(wxID_MORE); stdID(wxID_SETUP);
453 stdID(wxID_RESET); stdID(wxID_HELP_CONTEXT);
454 #undef stdID
455 else return XMLID(sid.c_str());
456 }
457
458
459 wxString wxXmlResourceHandler::GetName()
460 {
461 return m_Node->GetPropVal(_T("name"), _T("-1"));
462 }
463
464
465
466 bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv)
467 {
468 wxString v = GetParamValue(param);
469 v.MakeLower();
470 if (!v) return defaultv;
471 else return (v == _T("1"));
472 }
473
474
475
476 wxColour wxXmlResourceHandler::GetColour(const wxString& param)
477 {
478 wxString v = GetParamValue(param);
479 unsigned long tmp = 0;
480
481 if (v.Length() != 7 || v[0] != _T('#') ||
482 wxSscanf(v.c_str(), _T("#%lX"), &tmp) != 1)
483 {
484 wxLogError(_("XML resource: Incorrect colour specification '%s' for property '%s'."),
485 v.c_str(), param.c_str());
486 return wxNullColour;
487 }
488
489 return wxColour((tmp & 0xFF0000) >> 16 ,
490 (tmp & 0x00FF00) >> 8,
491 (tmp & 0x0000FF));
492 }
493
494
495 wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
496 {
497 wxXmlNode *n = m_Node->GetChildren();
498
499 while (n)
500 {
501 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
502 return n;
503 n = n->GetNext();
504 }
505 return NULL;
506 }
507
508
509 wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
510 {
511 wxXmlNode *n = node;
512 if (n == NULL) return wxEmptyString;
513 n = n->GetChildren();
514
515 while (n)
516 {
517 if (n->GetType() == wxXML_TEXT_NODE ||
518 n->GetType() == wxXML_CDATA_SECTION_NODE)
519 return n->GetContent();
520 n = n->GetNext();
521 }
522 return wxEmptyString;
523 }
524
525
526
527 wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
528 {
529 return GetNodeContent(GetParamNode(param));
530 }
531
532
533
534 wxSize wxXmlResourceHandler::GetSize(const wxString& param)
535 {
536 wxString s = GetParamValue(param);
537 if (s.IsEmpty()) s = _T("-1,-1");
538 bool is_dlg;
539 long sx, sy;
540
541 is_dlg = s[s.Length()-1] == _T('d');
542 if (is_dlg) s.RemoveLast();
543
544 if (!s.BeforeFirst(_T(',')).ToLong(&sx) ||
545 !s.AfterLast(_T(',')).ToLong(&sy))
546 {
547 wxLogError(_("Cannot parse coordinates from '%s'."), s.mb_str());
548 return wxDefaultSize;
549 }
550
551 if (is_dlg)
552 {
553 if (m_InstanceAsWindow)
554 return wxDLG_UNIT(m_InstanceAsWindow, wxSize(sx, sy));
555 else if (m_ParentAsWindow)
556 return wxDLG_UNIT(m_ParentAsWindow, wxSize(sx, sy));
557 else
558 {
559 wxLogError(_("Cannot convert dialog units: dialog unknown."));
560 return wxDefaultSize;
561 }
562 }
563 else return wxSize(sx, sy);
564 }
565
566
567
568 wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
569 {
570 wxSize sz = GetSize(param);
571 return wxPoint(sz.x, sz.y);
572 }
573
574
575
576 void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
577 {
578 //FIXME : add font, cursor
579
580 if (HasParam(_T("exstyle")))
581 wnd->SetExtraStyle(GetStyle(_T("exstyle")));
582 if (HasParam(_T("bg")))
583 wnd->SetBackgroundColour(GetColour(_T("bg")));
584 if (HasParam(_T("fg")))
585 wnd->SetForegroundColour(GetColour(_T("fg")));
586 if (GetBool(_T("enabled"), 1) == 0)
587 wnd->Enable(FALSE);
588 if (GetBool(_T("focused"), 0) == 1)
589 wnd->SetFocus();
590 if (GetBool(_T("hidden"), 0) == 1)
591 wnd->Show(FALSE);
592 #if wxUSE_TOOLTIPS
593 if (HasParam(_T("tooltip")))
594 wnd->SetToolTip(GetText(_T("tooltip")));
595 #endif
596 }
597
598
599 void wxXmlResourceHandler::CreateChildren(wxObject *parent,
600 bool only_this_handler, wxXmlNode *children_node)
601 {
602 if (children_node == NULL) children_node = GetParamNode(_T("children"));
603 if (children_node == NULL) return;
604
605 wxXmlNode *n = children_node->GetChildren();
606
607 while (n)
608 {
609 if (n->GetType() == wxXML_ELEMENT_NODE)
610 {
611 if (only_this_handler)
612 {
613 if (CanHandle(n))
614 CreateResource(n, parent, NULL);
615 }
616 else
617 m_Resource->CreateResFromNode(n, parent, NULL);
618 }
619 n = n->GetNext();
620 }
621 }
622
623
624
625
626
627
628
629
630
631 // --------------- XMLID implementation -----------------------------
632
633
634 #define XMLID_TABLE_SIZE 1024
635
636
637 struct XMLID_record
638 {
639 int id;
640 char *key;
641 XMLID_record *next;
642 };
643
644 static XMLID_record *XMLID_Records[XMLID_TABLE_SIZE] = {NULL};
645 static int XMLID_LastID = wxID_HIGHEST;
646
647 /*static*/ int wxXmlResource::GetXMLID(const char *str_id)
648 {
649 int index = 0;
650
651 for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
652 index %= XMLID_TABLE_SIZE;
653
654 XMLID_record *oldrec = NULL;
655 int matchcnt = 0;
656 for (XMLID_record *rec = XMLID_Records[index]; rec; rec = rec->next)
657 {
658 if (strcmp(rec->key, str_id) == 0)
659 {
660 #ifdef DEBUG_XMLID_HASH
661 printf("XMLID: matched '%s' (%ith item)\n", rec->key, matchcnt);
662 #endif
663 return rec->id;
664 }
665 matchcnt++;
666 oldrec = rec;
667 }
668
669 XMLID_record **rec_var = (oldrec == NULL) ?
670 &XMLID_Records[index] : &oldrec->next;
671 *rec_var = new XMLID_record;
672 (*rec_var)->id = ++XMLID_LastID;
673 (*rec_var)->key = strdup(str_id);
674 (*rec_var)->next = NULL;
675 #ifdef DEBUG_XMLID_HASH
676 printf("XMLID: new key for '%s': %i at %i (%ith item)\n",
677 (*rec_var)->key, (*rec_var)->id, index, matchcnt);
678 #endif
679
680 return (*rec_var)->id;
681 }
682
683
684 static void CleanXMLID_Record(XMLID_record *rec)
685 {
686 if (rec)
687 {
688 #ifdef DEBUG_XMLID_HASH
689 printf("XMLID: clearing '%s'\n", rec->key);
690 #endif
691 CleanXMLID_Record(rec->next);
692 free (rec->key);
693 delete rec;
694 }
695 }
696
697 static void CleanXMLID_Records()
698 {
699 for (int i = 0; i < XMLID_TABLE_SIZE; i++)
700 CleanXMLID_Record(XMLID_Records[i]);
701 }
702
703
704
705
706
707
708
709
710 // --------------- module and globals -----------------------------
711
712
713 static wxXmlResource gs_XmlResource;
714
715 wxXmlResource *wxTheXmlResource = &gs_XmlResource;
716
717
718 class wxXmlResourceModule: public wxModule
719 {
720 DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
721 public:
722 wxXmlResourceModule() {}
723 bool OnInit() {return TRUE;}
724 void OnExit()
725 {
726 wxTheXmlResource->ClearHandlers();
727 CleanXMLID_Records();
728 }
729 };
730
731 IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)