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