]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/xml/xmlres.cpp
ea00c03c756b0d7b68246fbc3a023a6b87a28516
[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::UpdateResources()
163 {
164 bool modif;
165 # if wxUSE_FILESYSTEM
166 wxFSFile *file;
167 wxFileSystem fsys;
168 # endif
169
170 for (size_t i = 0; i < m_Data.GetCount(); i++)
171 {
172 modif = (m_Data[i].Doc == NULL);
173
174 if (!modif)
175 {
176 # if wxUSE_FILESYSTEM
177 file = fsys.OpenFile(m_Data[i].File);
178 modif = file && file->GetModificationTime() > m_Data[i].Time;
179 if (!file)
180 wxLogError(_("Cannot open file '%s'."), m_Data[i].File.c_str());
181 delete file;
182 # else
183 modif = wxDateTime(wxFileModificationTime(m_Data[i].File)) > m_Data[i].Time;
184 # endif
185 }
186
187 if (modif)
188 {
189 wxInputStream *stream;
190
191 # if wxUSE_FILESYSTEM
192 file = fsys.OpenFile(m_Data[i].File);
193 stream = file->GetStream();
194 # else
195 stream = new wxFileInputStream(m_Data[i].File);
196 # endif
197
198 if (stream)
199 {
200 delete m_Data[i].Doc;
201 m_Data[i].Doc = new wxXmlDocument;
202 }
203 if (!stream || !m_Data[i].Doc->Load(*stream))
204 wxLogError(_("Cannot load resources from file '%s'."), m_Data[i].File.c_str());
205
206 if (m_Data[i].Doc->GetRoot()->GetName() != _T("resource"))
207 wxLogError(_("Invalid XML resource '%s': doesn't have root node 'resource'."), m_Data[i].File.c_str());
208
209 # if wxUSE_FILESYSTEM
210 delete file;
211 # else
212 delete stream;
213 # endif
214 }
215 }
216 }
217
218
219
220 wxXmlNode *wxXmlResource::FindResource(const wxString& name, const wxString& type)
221 {
222 UpdateResources(); //ensure everything is up-to-date
223
224 wxString dummy;
225 for (size_t f = 0; f < m_Data.GetCount(); f++)
226 {
227 for (wxXmlNode *node = m_Data[f].Doc->GetRoot()->GetChildren();
228 node; node = node->GetNext())
229 if ( node->GetType() == wxXML_ELEMENT_NODE &&
230 (!type || node->GetName() == type) &&
231 node->GetPropVal(wxT("name"), &dummy) &&
232 dummy == name &&
233 wxXmlResourceHandler::CheckPlatform(node))
234 return node;
235 }
236
237 wxLogError(_("XML resource '%s' (type '%s') not found!"),
238 name.c_str(), type.c_str());
239 return NULL;
240 }
241
242
243
244 wxObject *wxXmlResource::CreateResFromNode(wxXmlNode *node, wxObject *parent, wxObject *instance)
245 {
246 if (node == NULL) return NULL;
247
248 wxXmlResourceHandler *handler;
249 wxObject *ret;
250 wxNode * ND = m_Handlers.GetFirst();
251 while (ND)
252 {
253 handler = (wxXmlResourceHandler*)ND->GetData();
254 if (handler->CanHandle(node))
255 {
256 ret = handler->CreateResource(node, parent, instance);
257 if (ret) return ret;
258 }
259 ND = ND->GetNext();
260 }
261
262 wxLogError(_("No handler found for XML node '%s'!"), node->GetName().c_str());
263 return NULL;
264 }
265
266
267
268
269
270
271
272
273
274 wxXmlResourceHandler::wxXmlResourceHandler()
275 : m_Node(NULL), m_Parent(NULL), m_Instance(NULL),
276 m_ParentAsWindow(NULL), m_InstanceAsWindow(NULL)
277 {}
278
279
280
281 wxObject *wxXmlResourceHandler::CreateResource(wxXmlNode *node, wxObject *parent, wxObject *instance)
282 {
283 if (!CheckPlatform(node)) return NULL;
284
285 wxXmlNode *myNode = m_Node;
286 wxObject *myParent = m_Parent, *myInstance = m_Instance;
287 wxWindow *myParentAW = m_ParentAsWindow, *myInstanceAW = m_InstanceAsWindow;
288
289 m_Node = node;
290 m_Parent = parent;
291 m_Instance = instance;
292 m_ParentAsWindow = wxDynamicCast(m_Parent, wxWindow);
293 m_InstanceAsWindow = wxDynamicCast(m_Instance, wxWindow);
294
295 wxObject *returned = DoCreateResource();
296
297 m_Node = myNode;
298 m_Parent = myParent; m_ParentAsWindow = myParentAW;
299 m_Instance = myInstance; m_InstanceAsWindow = myInstanceAW;
300
301 return returned;
302 }
303
304
305
306 /*static*/ bool wxXmlResourceHandler::CheckPlatform(wxXmlNode *node)
307 {
308 wxString s;
309 if (!node->GetPropVal(_T("platform"), &s)) return TRUE;
310 #ifdef __WXMSW__
311 return s == wxString(_T("win"));
312 #elif defined(__UNIX__)
313 return s == wxString(_T("unix"));
314 #elif defined(__MAC__)
315 return s == wxString(_T("mac"));
316 #elif defined(__OS2__)
317 return s == wxString(_T("os2"));
318 #else
319 wxLogWarning(_("You're running the application on unknown platform, check for platfrom '%s' failed."), s.mb_str());
320 return TRUE; // unknown platform
321 #endif
322 }
323
324
325 void wxXmlResourceHandler::AddStyle(const wxString& name, int value)
326 {
327 m_StyleNames.Add(name);
328 m_StyleValues.Add(value);
329 }
330
331
332 bool wxXmlResourceHandler::HasParam(const wxString& param)
333 {
334 return (GetParamNode(param) != NULL);
335 }
336
337
338 int wxXmlResourceHandler::GetStyle(const wxString& param, int defaults)
339 {
340 wxString s = GetParamValue(param);
341
342 if (!s) return defaults;
343
344 wxStringTokenizer tkn(s, _T("| "), wxTOKEN_STRTOK);
345 int style = 0;
346 int index;
347 wxString fl;
348 while (tkn.HasMoreTokens())
349 {
350 fl = tkn.GetNextToken();
351 index = m_StyleNames.Index(fl);
352 if (index != wxNOT_FOUND)
353 style |= m_StyleValues[index];
354 else
355 wxLogError(_("Unknown style flag ") + fl);
356 }
357 return style;
358 }
359
360
361
362 wxString wxXmlResourceHandler::GetText(const wxString& param)
363 {
364 wxString str1 = GetParamValue(param);
365 wxString str2;
366 const wxChar *dt;
367
368 for (dt = str1.c_str(); *dt; dt++)
369 {
370 // Remap $ to &, map $$ to $ (for things like "&File..." --
371 // this is illegal in XML, so we use "$File..."):
372 if (*dt == '$')
373 switch (*(++dt))
374 {
375 case '$' : str2 << '$'; break;
376 default : str2 << '&' << *dt; break;
377 }
378 // Remap \n to CR, \r LF, \t to TAB:
379 else if (*dt == '\\')
380 switch (*(++dt))
381 {
382 case 'n' : str2 << '\n'; break;
383 case 't' : str2 << '\t'; break;
384 case 'r' : str2 << '\r'; break;
385 default : str2 << '\\' << *dt; break;
386 }
387 else str2 << *dt;
388 }
389 return str2;
390 }
391
392
393
394 long wxXmlResourceHandler::GetLong(const wxString& param, long defaultv)
395 {
396 long value;
397 wxString str1 = GetParamValue(param);
398
399 if (!str1.ToLong(&value))
400 value = defaultv;
401
402 return value;
403 }
404
405
406 int wxXmlResourceHandler::GetID()
407 {
408 wxString sid = GetName();
409 long num;
410
411 if (sid == _T("-1")) return -1;
412 else if (sid.IsNumber() && sid.ToLong(&num)) return num;
413 #define stdID(id) else if (sid == _T(#id)) return id
414 stdID(wxID_OPEN); stdID(wxID_CLOSE); stdID(wxID_NEW);
415 stdID(wxID_SAVE); stdID(wxID_SAVEAS); stdID(wxID_REVERT);
416 stdID(wxID_EXIT); stdID(wxID_UNDO); stdID(wxID_REDO);
417 stdID(wxID_HELP); stdID(wxID_PRINT); stdID(wxID_PRINT_SETUP);
418 stdID(wxID_PREVIEW); stdID(wxID_ABOUT); stdID(wxID_HELP_CONTENTS);
419 stdID(wxID_HELP_COMMANDS); stdID(wxID_HELP_PROCEDURES);
420 stdID(wxID_CUT); stdID(wxID_COPY); stdID(wxID_PASTE);
421 stdID(wxID_CLEAR); stdID(wxID_FIND); stdID(wxID_DUPLICATE);
422 stdID(wxID_SELECTALL); stdID(wxID_OK); stdID(wxID_CANCEL);
423 stdID(wxID_APPLY); stdID(wxID_YES); stdID(wxID_NO);
424 stdID(wxID_STATIC); stdID(wxID_FORWARD); stdID(wxID_BACKWARD);
425 stdID(wxID_DEFAULT); stdID(wxID_MORE); stdID(wxID_SETUP);
426 stdID(wxID_RESET); stdID(wxID_HELP_CONTEXT);
427 #undef stdID
428 else return XMLID(sid.c_str());
429 }
430
431
432 wxString wxXmlResourceHandler::GetName()
433 {
434 return m_Node->GetPropVal(_T("name"), _T("-1"));
435 }
436
437
438
439 bool wxXmlResourceHandler::GetBool(const wxString& param, bool defaultv)
440 {
441 wxString v = GetParamValue(param);
442 v.MakeLower();
443 if (!v) return defaultv;
444 else return v == _T("1") || v == _T("t") || v == _T("yes") ||
445 v == _T("on") || v == _T("true");
446 }
447
448
449
450 wxColour wxXmlResourceHandler::GetColour(const wxString& param)
451 {
452 wxString v = GetParamValue(param);
453 unsigned long tmp = 0;
454
455 if (v.Length() != 7 || v[0] != _T('#') ||
456 wxSscanf(v.c_str(), _T("#%lX"), &tmp) != 1)
457 {
458 wxLogError(_("XML resource: Incorrect colour specification '%s' for property '%s'."),
459 v.c_str(), param.c_str());
460 return wxNullColour;
461 }
462
463 return wxColour((tmp & 0xFF0000) >> 16 ,
464 (tmp & 0x00FF00) >> 8,
465 (tmp & 0x0000FF));
466 }
467
468
469 wxXmlNode *wxXmlResourceHandler::GetParamNode(const wxString& param)
470 {
471 wxXmlNode *n = m_Node->GetChildren();
472
473 while (n)
474 {
475 if (n->GetType() == wxXML_ELEMENT_NODE && n->GetName() == param)
476 return n;
477 n = n->GetNext();
478 }
479 return NULL;
480 }
481
482
483 wxString wxXmlResourceHandler::GetNodeContent(wxXmlNode *node)
484 {
485 wxXmlNode *n = node;
486 if (n == NULL) return wxEmptyString;
487 n = n->GetChildren();
488
489 while (n)
490 {
491 if (n->GetType() == wxXML_TEXT_NODE ||
492 n->GetType() == wxXML_CDATA_SECTION_NODE)
493 return n->GetContent();
494 n = n->GetNext();
495 }
496 return wxEmptyString;
497 }
498
499
500
501 wxString wxXmlResourceHandler::GetParamValue(const wxString& param)
502 {
503 return GetNodeContent(GetParamNode(param));
504 }
505
506
507
508 wxSize wxXmlResourceHandler::GetSize(const wxString& param)
509 {
510 wxString s = GetParamValue(param);
511 if (!s) s = _T("-1,-1");
512 bool is_dlg;
513 long sx, sy;
514
515 is_dlg = s[s.Length()-1] == _T('d');
516 if (is_dlg) s.RemoveLast();
517
518 if (!s.BeforeFirst(_T(',')).ToLong(&sx) ||
519 !s.AfterLast(_T(',')).ToLong(&sy))
520 {
521 wxLogError(_("Cannot parse coordinates from '%s'."), s.mb_str());
522 return wxDefaultSize;
523 }
524
525 if (is_dlg)
526 {
527 if (m_InstanceAsWindow)
528 return wxDLG_UNIT(m_InstanceAsWindow, wxSize(sx, sy));
529 else if (m_ParentAsWindow)
530 return wxDLG_UNIT(m_ParentAsWindow, wxSize(sx, sy));
531 else
532 {
533 wxLogError(_("Cannot convert dialog units: dialog unknown."));
534 return wxDefaultSize;
535 }
536 }
537 else return wxSize(sx, sy);
538 }
539
540
541
542 wxPoint wxXmlResourceHandler::GetPosition(const wxString& param)
543 {
544 wxSize sz = GetSize(param);
545 return wxPoint(sz.x, sz.y);
546 }
547
548
549
550 void wxXmlResourceHandler::SetupWindow(wxWindow *wnd)
551 {
552 //FIXME : add font, cursor
553
554 if (HasParam(_T("exstyle")))
555 wnd->SetExtraStyle(GetStyle(_T("exstyle")));
556 if (HasParam(_T("bg")))
557 wnd->SetBackgroundColour(GetColour(_T("bg")));
558 if (HasParam(_T("fg")))
559 wnd->SetForegroundColour(GetColour(_T("fg")));
560 if (GetBool(_T("enabled"), 1) == 0)
561 wnd->Enable(FALSE);
562 if (GetBool(_T("focused"), 0) == 1)
563 wnd->SetFocus();
564 if (GetBool(_T("hidden"), 0) == 1)
565 wnd->Show(FALSE);
566 #if wxUSE_TOOLTIPS
567 if (HasParam(_T("tooltip")))
568 wnd->SetToolTip(GetText(_T("tooltip")));
569 #endif
570 }
571
572
573 void wxXmlResourceHandler::CreateChildren(wxObject *parent,
574 bool only_this_handler, wxXmlNode *children_node)
575 {
576 if (children_node == NULL) children_node = GetParamNode(_T("children"));
577 if (children_node == NULL) return;
578
579 wxXmlNode *n = children_node->GetChildren();
580
581 while (n)
582 {
583 if (n->GetType() == wxXML_ELEMENT_NODE)
584 {
585 if (only_this_handler)
586 {
587 if (CanHandle(n))
588 CreateResource(n, parent, NULL);
589 }
590 else
591 m_Resource->CreateResFromNode(n, parent, NULL);
592 }
593 n = n->GetNext();
594 }
595 }
596
597
598
599
600
601
602
603
604
605 // --------------- XMLID implementation -----------------------------
606
607
608 #define XMLID_TABLE_SIZE 1024
609
610 struct XMLID_record
611 {
612 int id;
613 const char *key;
614 XMLID_record *next;
615 };
616
617 static XMLID_record *XMLID_Records[XMLID_TABLE_SIZE] = {NULL};
618 static int XMLID_LastID = wxID_HIGHEST;
619
620 /*static*/ int wxXmlResource::GetXMLID(const char *str_id)
621 {
622 int index = 0;
623
624 for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
625 index %= XMLID_TABLE_SIZE;
626
627 XMLID_record *oldrec = NULL;
628 for (XMLID_record *rec = XMLID_Records[index]; rec; rec = rec->next)
629 {
630 if (strcmp(rec->key, str_id) == 0) return rec->id;
631 oldrec = rec;
632 }
633
634 XMLID_record **rec_var = (oldrec == NULL) ?
635 &XMLID_Records[index] : &oldrec->next;
636 *rec_var = new XMLID_record;
637 (*rec_var)->id = ++XMLID_LastID;
638 (*rec_var)->key = str_id;
639 (*rec_var)->next = NULL;
640
641 return (*rec_var)->id;
642 }
643
644
645 static void CleanXMLID_Record(XMLID_record *rec)
646 {
647 if (rec)
648 {
649 CleanXMLID_Record(rec->next);
650 delete rec;
651 }
652 }
653
654 static void CleanXMLID_Records()
655 {
656 for (int i = 0; i < XMLID_TABLE_SIZE; i++)
657 CleanXMLID_Record(XMLID_Records[i]);
658 }
659
660
661
662
663
664
665
666
667 // --------------- module and globals -----------------------------
668
669
670 static wxXmlResource gs_XmlResource;
671
672 wxXmlResource *wxTheXmlResource = &gs_XmlResource;
673
674
675 class wxXmlResourceModule: public wxModule
676 {
677 DECLARE_DYNAMIC_CLASS(wxXmlResourceModule)
678 public:
679 wxXmlResourceModule() {}
680 bool OnInit() {return TRUE;}
681 void OnExit()
682 {
683 wxTheXmlResource->ClearHandlers();
684 CleanXMLID_Records();
685 }
686 };
687
688 IMPLEMENT_DYNAMIC_CLASS(wxXmlResourceModule, wxModule)