]> git.saurik.com Git - wxWidgets.git/blob - utils/wxprop/src/propform.cpp
*** empty log message ***
[wxWidgets.git] / utils / wxprop / src / propform.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: propform.cpp
3 // Purpose: Property form classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "propform.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <string.h>
31
32 #if defined(__WINDOWS__) && !defined(__GNUWIN32__)
33 #include <strstrea.h>
34 #else
35 #include <strstream.h>
36 #endif
37
38 #include "wx/window.h"
39 #include "wx/utils.h"
40 #include "wx/list.h"
41 #include "propform.h"
42
43 /*
44 * Property view
45 */
46
47 IMPLEMENT_DYNAMIC_CLASS(wxPropertyFormView, wxPropertyView)
48
49 BEGIN_EVENT_TABLE(wxPropertyFormView, wxPropertyView)
50 EVT_BUTTON(wxID_OK, wxPropertyFormView::OnOk)
51 EVT_BUTTON(wxID_CANCEL, wxPropertyFormView::OnCancel)
52 EVT_BUTTON(wxID_HELP, wxPropertyFormView::OnHelp)
53 EVT_BUTTON(wxID_PROP_REVERT, wxPropertyFormView::OnRevert)
54 EVT_BUTTON(wxID_PROP_UPDATE, wxPropertyFormView::OnUpdate)
55 END_EVENT_TABLE()
56
57 bool wxPropertyFormView::dialogCancelled = FALSE;
58
59 wxPropertyFormView::wxPropertyFormView(wxWindow *propPanel, long flags):wxPropertyView(flags)
60 {
61 propertyWindow = propPanel;
62 managedWindow = NULL;
63
64 windowCloseButton = NULL;
65 windowCancelButton = NULL;
66 windowHelpButton = NULL;
67
68 detailedEditing = FALSE;
69 }
70
71 wxPropertyFormView::~wxPropertyFormView(void)
72 {
73 }
74
75 void wxPropertyFormView::ShowView(wxPropertySheet *ps, wxWindow *panel)
76 {
77 propertySheet = ps;
78
79 AssociatePanel(panel);
80 // CreateControls();
81 // UpdatePropertyList();
82 }
83
84 // Update this view of the viewed object, called e.g. by
85 // the object itself.
86 bool wxPropertyFormView::OnUpdateView(void)
87 {
88 return TRUE;
89 }
90
91 bool wxPropertyFormView::Check(void)
92 {
93 if (!propertySheet)
94 return FALSE;
95
96 wxNode *node = propertySheet->GetProperties().First();
97 while (node)
98 {
99 wxProperty *prop = (wxProperty *)node->Data();
100 wxPropertyValidator *validator = FindPropertyValidator(prop);
101 if (validator && validator->IsKindOf(CLASSINFO(wxPropertyFormValidator)))
102 {
103 wxPropertyFormValidator *formValidator = (wxPropertyFormValidator *)validator;
104 if (!formValidator->OnCheckValue(prop, this, propertyWindow))
105 return FALSE;
106 }
107 node = node->Next();
108 }
109 return TRUE;
110 }
111
112 bool wxPropertyFormView::TransferToPropertySheet(void)
113 {
114 if (!propertySheet)
115 return FALSE;
116
117 wxNode *node = propertySheet->GetProperties().First();
118 while (node)
119 {
120 wxProperty *prop = (wxProperty *)node->Data();
121 wxPropertyValidator *validator = FindPropertyValidator(prop);
122 if (validator && validator->IsKindOf(CLASSINFO(wxPropertyFormValidator)))
123 {
124 wxPropertyFormValidator *formValidator = (wxPropertyFormValidator *)validator;
125 formValidator->OnRetrieveValue(prop, this, propertyWindow);
126 }
127 node = node->Next();
128 }
129 return TRUE;
130 }
131
132 bool wxPropertyFormView::TransferToDialog(void)
133 {
134 if (!propertySheet)
135 return FALSE;
136
137 wxNode *node = propertySheet->GetProperties().First();
138 while (node)
139 {
140 wxProperty *prop = (wxProperty *)node->Data();
141 wxPropertyValidator *validator = FindPropertyValidator(prop);
142 if (validator && validator->IsKindOf(CLASSINFO(wxPropertyFormValidator)))
143 {
144 wxPropertyFormValidator *formValidator = (wxPropertyFormValidator *)validator;
145 formValidator->OnDisplayValue(prop, this, propertyWindow);
146 }
147 node = node->Next();
148 }
149 return TRUE;
150 }
151
152 bool wxPropertyFormView::AssociateNames(void)
153 {
154 if (!propertySheet || !propertyWindow)
155 return FALSE;
156
157 wxNode *node = propertyWindow->GetChildren()->First();
158 while (node)
159 {
160 wxWindow *win = (wxWindow *)node->Data();
161 if (win->GetName() != "")
162 {
163 wxProperty *prop = propertySheet->GetProperty(win->GetName());
164 if (prop)
165 prop->SetWindow(win);
166 }
167 node = node->Next();
168 }
169 return TRUE;
170 }
171
172
173 bool wxPropertyFormView::OnClose(void)
174 {
175 delete this;
176 return TRUE;
177 }
178
179 void wxPropertyFormView::OnOk(wxCommandEvent& event)
180 {
181 // Retrieve the value if any
182 if (!Check())
183 return;
184
185 dialogCancelled = FALSE;
186
187 managedWindow->Close(TRUE);
188 }
189
190 void wxPropertyFormView::OnCancel(wxCommandEvent& event)
191 {
192 dialogCancelled = TRUE;
193
194 managedWindow->Close(TRUE);
195 }
196
197 void wxPropertyFormView::OnHelp(wxCommandEvent& event)
198 {
199 }
200
201 void wxPropertyFormView::OnUpdate(wxCommandEvent& event)
202 {
203 TransferToPropertySheet();
204 }
205
206 void wxPropertyFormView::OnRevert(wxCommandEvent& event)
207 {
208 TransferToDialog();
209 }
210
211 void wxPropertyFormView::OnCommand(wxWindow& win, wxCommandEvent& event)
212 {
213 if (!propertySheet)
214 return;
215
216 if (win.GetName() == "")
217 return;
218
219 if (strcmp(win.GetName(), "ok") == 0)
220 OnOk(event);
221 else if (strcmp(win.GetName(), "cancel") == 0)
222 OnCancel(event);
223 else if (strcmp(win.GetName(), "help") == 0)
224 OnHelp(event);
225 else if (strcmp(win.GetName(), "update") == 0)
226 OnUpdate(event);
227 else if (strcmp(win.GetName(), "revert") == 0)
228 OnRevert(event);
229 else
230 {
231 // Find a validator to route the command to.
232 wxNode *node = propertySheet->GetProperties().First();
233 while (node)
234 {
235 wxProperty *prop = (wxProperty *)node->Data();
236 if (prop->GetWindow() && (prop->GetWindow() == &win))
237 {
238 wxPropertyValidator *validator = FindPropertyValidator(prop);
239 if (validator && validator->IsKindOf(CLASSINFO(wxPropertyFormValidator)))
240 {
241 wxPropertyFormValidator *formValidator = (wxPropertyFormValidator *)validator;
242 formValidator->OnCommand(prop, this, propertyWindow, event);
243 return;
244 }
245 }
246 node = node->Next();
247 }
248 }
249 }
250
251 void wxPropertyFormView::OnDoubleClick(wxControl *item)
252 {
253 if (!propertySheet)
254 return;
255
256 // Find a validator to route the command to.
257 wxNode *node = propertySheet->GetProperties().First();
258 while (node)
259 {
260 wxProperty *prop = (wxProperty *)node->Data();
261 if (prop->GetWindow() && ((wxControl *)prop->GetWindow() == item))
262 {
263 wxPropertyValidator *validator = FindPropertyValidator(prop);
264 if (validator && validator->IsKindOf(CLASSINFO(wxPropertyFormValidator)))
265 {
266 wxPropertyFormValidator *formValidator = (wxPropertyFormValidator *)validator;
267 formValidator->OnDoubleClick(prop, this, propertyWindow);
268 return;
269 }
270 }
271 node = node->Next();
272 }
273 }
274
275 /*
276 * Property form dialog box
277 */
278
279 IMPLEMENT_CLASS(wxPropertyFormDialog, wxDialog)
280
281 wxPropertyFormDialog::wxPropertyFormDialog(wxPropertyFormView *v, wxWindow *parent, const wxString& title,
282 const wxPoint& pos, const wxSize& size, long style, const wxString& name):
283 wxDialog(parent, -1, title, pos, size, style, name)
284 {
285 view = v;
286 view->AssociatePanel(this);
287 view->SetManagedWindow(this);
288 // SetAutoLayout(TRUE);
289 }
290
291 bool wxPropertyFormDialog::OnClose(void)
292 {
293 if (view)
294 {
295 view->OnClose();
296 view = NULL;
297 return TRUE;
298 }
299 else
300 return FALSE;
301 }
302
303 void wxPropertyFormDialog::OnDefaultAction(wxControl *item)
304 {
305 view->OnDoubleClick(item);
306 }
307
308 void wxPropertyFormDialog::OnCommand(wxWindow& win, wxCommandEvent& event)
309 {
310 if ( view )
311 view->OnCommand(win, event);
312 }
313
314 // Extend event processing to search the view's event table
315 bool wxPropertyFormDialog::ProcessEvent(wxEvent& event)
316 {
317 if ( !view || ! view->ProcessEvent(event) )
318 return wxEvtHandler::ProcessEvent(event);
319 else
320 return TRUE;
321 }
322
323
324 /*
325 * Property form panel
326 */
327
328 IMPLEMENT_CLASS(wxPropertyFormPanel, wxPanel)
329
330 void wxPropertyFormPanel::OnDefaultAction(wxControl *item)
331 {
332 view->OnDoubleClick(item);
333 }
334
335 void wxPropertyFormPanel::OnCommand(wxWindow& win, wxCommandEvent& event)
336 {
337 view->OnCommand(win, event);
338 }
339
340 // Extend event processing to search the view's event table
341 bool wxPropertyFormPanel::ProcessEvent(wxEvent& event)
342 {
343 if ( !view || ! view->ProcessEvent(event) )
344 return wxEvtHandler::ProcessEvent(event);
345 else
346 return TRUE;
347 }
348
349 /*
350 * Property frame
351 */
352
353 IMPLEMENT_CLASS(wxPropertyFormFrame, wxFrame)
354
355 bool wxPropertyFormFrame::OnClose(void)
356 {
357 if (view)
358 return view->OnClose();
359 else
360 return FALSE;
361 }
362
363 wxPanel *wxPropertyFormFrame::OnCreatePanel(wxFrame *parent, wxPropertyFormView *v)
364 {
365 return new wxPropertyFormPanel(v, parent);
366 }
367
368 bool wxPropertyFormFrame::Initialize(void)
369 {
370 propertyPanel = OnCreatePanel(this, view);
371 if (propertyPanel)
372 {
373 view->AssociatePanel(propertyPanel);
374 view->SetManagedWindow(this);
375 // propertyPanel->SetAutoLayout(TRUE);
376 return TRUE;
377 }
378 else
379 return FALSE;
380 }
381
382 /*
383 * Property form specific validator
384 */
385
386 IMPLEMENT_ABSTRACT_CLASS(wxPropertyFormValidator, wxPropertyValidator)
387
388
389 /*
390 * Default validators
391 */
392
393 IMPLEMENT_DYNAMIC_CLASS(wxRealFormValidator, wxPropertyFormValidator)
394
395 ///
396 /// Real number form validator
397 ///
398 bool wxRealFormValidator::OnCheckValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
399 {
400 if (realMin == 0.0 && realMax == 0.0)
401 return TRUE;
402
403 // The item used for viewing the real number: should be a text item.
404 wxWindow *propertyWindow = property->GetWindow();
405 if (!propertyWindow || !propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
406 return FALSE;
407
408 wxString value(((wxTextCtrl *)propertyWindow)->GetValue());
409
410 float val = 0.0;
411 if (!StringToFloat(WXSTRINGCAST value, &val))
412 {
413 char buf[200];
414 sprintf(buf, "Value %s is not a valid real number!", (const char *)value);
415 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
416 return FALSE;
417 }
418
419 if (val < realMin || val > realMax)
420 {
421 char buf[200];
422 sprintf(buf, "Value must be a real number between %.2f and %.2f!", realMin, realMax);
423 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
424 return FALSE;
425 }
426 return TRUE;
427 }
428
429 bool wxRealFormValidator::OnRetrieveValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
430 {
431 // The item used for viewing the real number: should be a text item.
432 wxWindow *propertyWindow = property->GetWindow();
433 if (!propertyWindow || !propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
434 return FALSE;
435
436 wxString value(((wxTextCtrl *)propertyWindow)->GetValue());
437
438 if (value.Length() == 0)
439 return FALSE;
440
441 float f = (float)atof((const char *)value);
442 property->GetValue() = f;
443 return TRUE;
444 }
445
446 bool wxRealFormValidator::OnDisplayValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
447 {
448 // The item used for viewing the real number: should be a text item.
449 wxWindow *propertyWindow = property->GetWindow();
450 if (!propertyWindow || !propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
451 return FALSE;
452
453 wxTextCtrl *textItem = (wxTextCtrl *)propertyWindow;
454 textItem->SetValue(FloatToString(property->GetValue().RealValue()));
455 return TRUE;
456 }
457
458 ///
459 /// Integer validator
460 ///
461 IMPLEMENT_DYNAMIC_CLASS(wxIntegerFormValidator, wxPropertyFormValidator)
462
463 bool wxIntegerFormValidator::OnCheckValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
464 {
465 if (integerMin == 0.0 && integerMax == 0.0)
466 return TRUE;
467
468 // The item used for viewing the real number: should be a text item or a slider
469 wxWindow *propertyWindow = property->GetWindow();
470 if (!propertyWindow)
471 return FALSE;
472
473 long val = 0;
474
475 if (propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
476 {
477 wxString value(((wxTextCtrl *)propertyWindow)->GetValue());
478
479 if (!StringToLong(WXSTRINGCAST value, &val))
480 {
481 char buf[200];
482 sprintf(buf, "Value %s is not a valid integer!", (const char *)value);
483 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
484 return FALSE;
485 }
486 }
487 else if (propertyWindow->IsKindOf(CLASSINFO(wxSlider)))
488 {
489 val = (long)((wxSlider *)propertyWindow)->GetValue();
490 }
491 else
492 return FALSE;
493
494 if (val < integerMin || val > integerMax)
495 {
496 char buf[200];
497 sprintf(buf, "Value must be an integer between %ld and %ld!", integerMin, integerMax);
498 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
499 return FALSE;
500 }
501 return TRUE;
502 }
503
504 bool wxIntegerFormValidator::OnRetrieveValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
505 {
506 // The item used for viewing the real number: should be a text item or a slider
507 wxWindow *propertyWindow = property->GetWindow();
508 if (!propertyWindow)
509 return FALSE;
510
511 if (propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
512 {
513 wxString value(((wxTextCtrl *)propertyWindow)->GetValue());
514
515 if (value.Length() == 0)
516 return FALSE;
517
518 long i = atol((const char *)value);
519 property->GetValue() = i;
520 }
521 else if (propertyWindow->IsKindOf(CLASSINFO(wxSlider)))
522 {
523 property->GetValue() = (long)((wxSlider *)propertyWindow)->GetValue();
524 }
525 else
526 return FALSE;
527
528 return TRUE;
529 }
530
531 bool wxIntegerFormValidator::OnDisplayValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
532 {
533 // The item used for viewing the real number: should be a text item or a slider
534 wxWindow *propertyWindow = property->GetWindow();
535 if (!propertyWindow)
536 return FALSE;
537
538 if (propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
539 {
540 wxTextCtrl *textItem = (wxTextCtrl *)propertyWindow;
541 textItem->SetValue(LongToString(property->GetValue().IntegerValue()));
542 }
543 else if (propertyWindow->IsKindOf(CLASSINFO(wxSlider)))
544 {
545 ((wxSlider *)propertyWindow)->SetValue((int)property->GetValue().IntegerValue());
546 }
547 else
548 return FALSE;
549 return TRUE;
550 }
551
552 ///
553 /// Boolean validator
554 ///
555 IMPLEMENT_DYNAMIC_CLASS(wxBoolFormValidator, wxPropertyFormValidator)
556
557 bool wxBoolFormValidator::OnCheckValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
558 {
559 // The item used for viewing the boolean: should be a checkbox
560 wxWindow *propertyWindow = property->GetWindow();
561 if (!propertyWindow || !propertyWindow->IsKindOf(CLASSINFO(wxCheckBox)))
562 return FALSE;
563
564 return TRUE;
565 }
566
567 bool wxBoolFormValidator::OnRetrieveValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
568 {
569 // The item used for viewing the boolean: should be a checkbox.
570 wxWindow *propertyWindow = property->GetWindow();
571 if (!propertyWindow || !propertyWindow->IsKindOf(CLASSINFO(wxCheckBox)))
572 return FALSE;
573
574 wxCheckBox *checkBox = (wxCheckBox *)propertyWindow;
575
576 property->GetValue() = (bool)checkBox->GetValue();
577 return TRUE;
578 }
579
580 bool wxBoolFormValidator::OnDisplayValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
581 {
582 // The item used for viewing the boolean: should be a checkbox.
583 wxWindow *propertyWindow = property->GetWindow();
584 if (!propertyWindow || !propertyWindow->IsKindOf(CLASSINFO(wxCheckBox)))
585 return FALSE;
586
587 wxCheckBox *checkBox = (wxCheckBox *)propertyWindow;
588 checkBox->SetValue((bool)property->GetValue().BoolValue());
589 return TRUE;
590 }
591
592 ///
593 /// String validator
594 ///
595 IMPLEMENT_DYNAMIC_CLASS(wxStringFormValidator, wxPropertyFormValidator)
596
597 wxStringFormValidator::wxStringFormValidator(wxStringList *list, long flags):
598 wxPropertyFormValidator(flags)
599 {
600 strings = list;
601 }
602
603 bool wxStringFormValidator::OnCheckValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
604 {
605 if (!strings)
606 return TRUE;
607
608 // The item used for viewing the string: should be a text item, choice item or listbox.
609 wxWindow *propertyWindow = property->GetWindow();
610 if (!propertyWindow)
611 return FALSE;
612 if (propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
613 {
614 wxTextCtrl *text = (wxTextCtrl *)propertyWindow;
615 if (!strings->Member(text->GetValue()))
616 {
617 wxString s("Value ");
618 s += text->GetValue();
619 s += " is not valid.";
620 wxMessageBox(s, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
621 return FALSE;
622 }
623 }
624 else
625 {
626 // Any other item constrains the string value,
627 // so we don't have to check it.
628 }
629 return TRUE;
630 }
631
632 bool wxStringFormValidator::OnRetrieveValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
633 {
634 // The item used for viewing the string: should be a text item, choice item or listbox.
635 wxWindow *propertyWindow = property->GetWindow();
636 if (!propertyWindow)
637 return FALSE;
638 if (propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
639 {
640 wxTextCtrl *text = (wxTextCtrl *)propertyWindow;
641 property->GetValue() = text->GetValue();
642 }
643 else if (propertyWindow->IsKindOf(CLASSINFO(wxListBox)))
644 {
645 wxListBox *lbox = (wxListBox *)propertyWindow;
646 if (lbox->GetSelection() > -1)
647 property->GetValue() = lbox->GetStringSelection();
648 }
649 /*
650 else if (propertyWindow->IsKindOf(CLASSINFO(wxRadioBox)))
651 {
652 wxRadioBox *rbox = (wxRadioBox *)propertyWindow;
653 int n = 0;
654 if ((n = rbox->GetSelection()) > -1)
655 property->GetValue() = rbox->GetString(n);
656 }
657 */
658 else if (propertyWindow->IsKindOf(CLASSINFO(wxChoice)))
659 {
660 wxChoice *choice = (wxChoice *)propertyWindow;
661 if (choice->GetSelection() > -1)
662 property->GetValue() = choice->GetStringSelection();
663 }
664 else
665 return FALSE;
666 return TRUE;
667 }
668
669 bool wxStringFormValidator::OnDisplayValue(wxProperty *property, wxPropertyFormView *view, wxWindow *parentWindow)
670 {
671 // The item used for viewing the string: should be a text item, choice item or listbox.
672 wxWindow *propertyWindow = property->GetWindow();
673 if (!propertyWindow)
674 return FALSE;
675 if (propertyWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
676 {
677 wxTextCtrl *text = (wxTextCtrl *)propertyWindow;
678 text->SetValue(property->GetValue().StringValue());
679 }
680 else if (propertyWindow->IsKindOf(CLASSINFO(wxListBox)))
681 {
682 wxListBox *lbox = (wxListBox *)propertyWindow;
683 if (lbox->Number() == 0 && strings)
684 {
685 // Try to initialize the listbox from 'strings'
686 wxNode *node = strings->First();
687 while (node)
688 {
689 char *s = (char *)node->Data();
690 lbox->Append(s);
691 node = node->Next();
692 }
693 }
694 lbox->SetStringSelection(property->GetValue().StringValue());
695 }
696 /*
697 else if (propertyWindow->IsKindOf(CLASSINFO(wxRadioBox)))
698 {
699 wxRadioBox *rbox = (wxRadioBox *)propertyWindow;
700 rbox->SetStringSelection(property->GetValue().StringValue());
701 }
702 */
703 else if (propertyWindow->IsKindOf(CLASSINFO(wxChoice)))
704 {
705 wxChoice *choice = (wxChoice *)propertyWindow;
706 #ifndef __XVIEW__
707 if (choice->Number() == 0 && strings)
708 {
709 // Try to initialize the choice item from 'strings'
710 // XView doesn't allow this kind of thing.
711 wxNode *node = strings->First();
712 while (node)
713 {
714 char *s = (char *)node->Data();
715 choice->Append(s);
716 node = node->Next();
717 }
718 }
719 #endif
720 choice->SetStringSelection(property->GetValue().StringValue());
721 }
722 else
723 return FALSE;
724 return TRUE;
725 }
726