]> git.saurik.com Git - wxWidgets.git/blame - src/generic/proplist.cpp
Added test for long long type. (Really trivial, see setup.h: SIZEOF_xxx)
[wxWidgets.git] / src / generic / proplist.cpp
CommitLineData
e3a43801
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: proplist.cpp
3// Purpose: Property list 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 licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "proplist.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 wxUSE_IOSTREAMH
33#if defined(__WXMSW__) && !defined(__GNUWIN32__)
34#include <strstrea.h>
35#else
36#include <strstream.h>
37#endif
38#else
39#include <strstream>
40#endif
41
42#include "wx/window.h"
43#include "wx/utils.h"
44#include "wx/list.h"
45#include "wx/colordlg.h"
46#include "wx/proplist.h"
47
48/*
49 * Property text edit control
50 */
51
52IMPLEMENT_CLASS(wxPropertyTextEdit, wxTextCtrl)
53
54wxPropertyTextEdit::wxPropertyTextEdit(wxPropertyListView *v, wxWindow *parent,
55 const wxWindowID id, const wxString& value,
56 const wxPoint& pos, const wxSize& size,
57 long style, const wxString& name):
58 wxTextCtrl(parent, id, value, pos, size, style, wxDefaultValidator, name)
59{
60 m_view = v;
61}
62
63void wxPropertyTextEdit::OnSetFocus(void)
64{
65}
66
67void wxPropertyTextEdit::OnKillFocus(void)
68{
69}
70
71/*
72 * Property list view
73 */
74
75IMPLEMENT_DYNAMIC_CLASS(wxPropertyListView, wxPropertyView)
76
77BEGIN_EVENT_TABLE(wxPropertyListView, wxPropertyView)
78 EVT_BUTTON(wxID_OK, wxPropertyListView::OnOk)
79 EVT_BUTTON(wxID_CANCEL, wxPropertyListView::OnCancel)
80 EVT_BUTTON(wxID_HELP, wxPropertyListView::OnHelp)
81 EVT_BUTTON(wxID_PROP_CROSS, wxPropertyListView::OnCross)
82 EVT_BUTTON(wxID_PROP_CHECK, wxPropertyListView::OnCheck)
83 EVT_BUTTON(wxID_PROP_EDIT, wxPropertyListView::OnEdit)
84 EVT_TEXT_ENTER(wxID_PROP_TEXT, wxPropertyListView::OnText)
85 EVT_LISTBOX(wxID_PROP_SELECT, wxPropertyListView::OnPropertySelect)
86 EVT_COMMAND(wxID_PROP_SELECT, wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxPropertyListView::OnPropertyDoubleClick)
87 EVT_LISTBOX(wxID_PROP_VALUE_SELECT, wxPropertyListView::OnValueListSelect)
88END_EVENT_TABLE()
89
90bool wxPropertyListView::sm_dialogCancelled = FALSE;
91wxBitmap *wxPropertyListView::sm_tickBitmap = NULL;
92wxBitmap *wxPropertyListView::sm_crossBitmap = NULL;
93
94wxPropertyListView::wxPropertyListView(wxPanel *propPanel, long flags):wxPropertyView(flags)
95{
96 m_propertyScrollingList = NULL;
97 m_valueList = NULL;
98 m_valueText = NULL;
99 m_editButton = NULL;
100 m_confirmButton = NULL;
101 m_cancelButton = NULL;
102 m_propertyWindow = propPanel;
103 m_managedWindow = NULL;
104
105 m_windowCloseButton = NULL;
106 m_windowCancelButton = NULL;
107 m_windowHelpButton = NULL;
108
109 m_detailedEditing = FALSE;
110}
111
112wxPropertyListView::~wxPropertyListView(void)
113{
114/*
115 if (m_tickBitmap)
116 delete m_tickBitmap;
117 if (m_crossBitmap)
118 delete m_crossBitmap;
119*/
120}
121
122void wxPropertyListView::ShowView(wxPropertySheet *ps, wxPanel *panel)
123{
124 m_propertySheet = ps;
125
126 AssociatePanel(panel);
127 CreateControls();
128
129 UpdatePropertyList();
130 panel->Layout();
131}
132
133// Update this view of the viewed object, called e.g. by
134// the object itself.
135bool wxPropertyListView::OnUpdateView(void)
136{
137 return TRUE;
138}
139
140bool wxPropertyListView::UpdatePropertyList(bool clearEditArea)
141{
142 if (!m_propertyScrollingList || !m_propertySheet)
143 return FALSE;
144
145 m_propertyScrollingList->Clear();
146 if (clearEditArea)
147 {
148 m_valueList->Clear();
149 m_valueText->SetValue("");
150 }
151 wxNode *node = m_propertySheet->GetProperties().First();
152
153 // Should sort them... later...
154 while (node)
155 {
156 wxProperty *property = (wxProperty *)node->Data();
157 wxString stringValueRepr(property->GetValue().GetStringRepresentation());
158 wxString paddedString(MakeNameValueString(property->GetName(), stringValueRepr));
159
160 m_propertyScrollingList->Append(paddedString.GetData(), (char *)property);
161 node = node->Next();
162 }
163 return TRUE;
164}
165
166bool wxPropertyListView::UpdatePropertyDisplayInList(wxProperty *property)
167{
168 if (!m_propertyScrollingList || !m_propertySheet)
169 return FALSE;
170
8710cf5c 171#ifdef __WXMSW__
e3a43801 172 int currentlySelected = m_propertyScrollingList->GetSelection();
8710cf5c 173#endif
e3a43801
JS
174// #ifdef __WXMSW__
175 wxString stringValueRepr(property->GetValue().GetStringRepresentation());
176 wxString paddedString(MakeNameValueString(property->GetName(), stringValueRepr));
177 int sel = FindListIndexForProperty(property);
178
179 if (sel > -1)
180 {
181 // Don't update the listbox unnecessarily because it can cause
182 // ugly flashing.
183
184 if (paddedString != m_propertyScrollingList->GetString(sel))
185 m_propertyScrollingList->SetString(sel, paddedString.GetData());
186 }
187//#else
188// UpdatePropertyList(FALSE);
189//#endif
190
191 // TODO: why is this necessary?
192#ifdef __WXMSW__
193 if (currentlySelected > -1)
194 m_propertyScrollingList->SetSelection(currentlySelected);
195#endif
196
197 return TRUE;
198}
199
200// Find the wxListBox index corresponding to this property
201int wxPropertyListView::FindListIndexForProperty(wxProperty *property)
202{
203 int n = m_propertyScrollingList->Number();
204 for (int i = 0; i < n; i++)
205 {
206 if (property == (wxProperty *)m_propertyScrollingList->wxListBox::GetClientData(i))
207 return i;
208 }
209 return -1;
210}
211
212wxString wxPropertyListView::MakeNameValueString(wxString name, wxString value)
213{
214 wxString theString(name);
215
216 int nameWidth = 25;
217 int padWith = nameWidth - theString.Length();
218 if (padWith < 0)
219 padWith = 0;
220
221 if (GetFlags() & wxPROP_SHOWVALUES)
222 {
223 // Want to pad with spaces
224 theString.Append(' ', padWith);
225 theString += value;
226 }
227
228 return theString;
229}
230
231// Select and show string representation in validator the given
232// property. NULL resets to show no property.
233bool wxPropertyListView::ShowProperty(wxProperty *property, bool select)
234{
235 if (m_currentProperty)
236 {
237 EndShowingProperty(m_currentProperty);
238 m_currentProperty = NULL;
239 }
240
241 m_valueList->Clear();
242 m_valueText->SetValue("");
243
244 if (property)
245 {
246 m_currentProperty = property;
247 BeginShowingProperty(property);
248 }
249 if (select)
250 {
251 int sel = FindListIndexForProperty(property);
252 if (sel > -1)
253 m_propertyScrollingList->SetSelection(sel);
254 }
255 return TRUE;
256}
257
258// Find appropriate validator and load property into value controls
259bool wxPropertyListView::BeginShowingProperty(wxProperty *property)
260{
261 m_currentValidator = FindPropertyValidator(property);
262 if (!m_currentValidator)
263 return FALSE;
264
265 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
266 return FALSE;
267
268 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
269
270 listValidator->OnPrepareControls(property, this, m_propertyWindow);
271 DisplayProperty(property);
272 return TRUE;
273}
274
275// Find appropriate validator and unload property from value controls
276bool wxPropertyListView::EndShowingProperty(wxProperty *property)
277{
278 if (!m_currentValidator)
279 return FALSE;
280
281 RetrieveProperty(property);
282
283 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
284 return FALSE;
285
286 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
287
288 listValidator->OnClearControls(property, this, m_propertyWindow);
289 if (m_detailedEditing)
290 {
291 listValidator->OnClearDetailControls(property, this, m_propertyWindow);
292 m_detailedEditing = FALSE;
293 }
294 return TRUE;
295}
296
297void wxPropertyListView::BeginDetailedEditing(void)
298{
299 if (!m_currentValidator)
300 return;
301 if (!m_currentProperty)
302 return;
303 if (m_detailedEditing)
304 return;
305 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
306 return;
307 if (!m_currentProperty->IsEnabled())
308 return;
309
310 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
311
312 if (listValidator->OnPrepareDetailControls(m_currentProperty, this, m_propertyWindow))
313 m_detailedEditing = TRUE;
314}
315
316void wxPropertyListView::EndDetailedEditing(void)
317{
318 if (!m_currentValidator)
319 return;
320 if (!m_currentProperty)
321 return;
322
323 RetrieveProperty(m_currentProperty);
324
325 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
326 return;
327
328 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
329
330 if (m_detailedEditing)
331 {
332 listValidator->OnClearDetailControls(m_currentProperty, this, m_propertyWindow);
333 m_detailedEditing = FALSE;
334 }
335}
336
337bool wxPropertyListView::DisplayProperty(wxProperty *property)
338{
339 if (!m_currentValidator)
340 return FALSE;
341
342 if (((m_currentValidator->GetFlags() & wxPROP_ALLOW_TEXT_EDITING) == 0) || !property->IsEnabled())
343 m_valueText->SetEditable(FALSE);
344 else
345 m_valueText->SetEditable(TRUE);
346
347 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
348 return FALSE;
349
350 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
351
352 listValidator->OnDisplayValue(property, this, m_propertyWindow);
353 return TRUE;
354}
355
356bool wxPropertyListView::RetrieveProperty(wxProperty *property)
357{
358 if (!m_currentValidator)
359 return FALSE;
360 if (!property->IsEnabled())
361 return FALSE;
362
363 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
364 return FALSE;
365
366 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
367
368 if (listValidator->OnCheckValue(property, this, m_propertyWindow))
369 {
370 if (listValidator->OnRetrieveValue(property, this, m_propertyWindow))
371 {
372 UpdatePropertyDisplayInList(property);
373 OnPropertyChanged(property);
374 }
375 }
376 else
377 {
378 // Revert to old value
379 listValidator->OnDisplayValue(property, this, m_propertyWindow);
380 }
381 return TRUE;
382}
383
384
385bool wxPropertyListView::EditProperty(wxProperty *WXUNUSED(property))
386{
387 return TRUE;
388}
389
390// Called by the listbox callback
391void wxPropertyListView::OnPropertySelect(wxCommandEvent& WXUNUSED(event))
392{
393 int sel = m_propertyScrollingList->GetSelection();
394 if (sel > -1)
395 {
396 wxProperty *newSel = (wxProperty *)m_propertyScrollingList->wxListBox::GetClientData(sel);
397 if (newSel && newSel != m_currentProperty)
398 {
399 ShowProperty(newSel, FALSE);
400 }
401 }
402}
403
404bool wxPropertyListView::CreateControls(void)
405{
406 wxPanel *panel = (wxPanel *)m_propertyWindow;
407
408 int largeButtonWidth = 60;
409 int largeButtonHeight = 25;
410
411 int smallButtonWidth = 25;
412 int smallButtonHeight = 20;
413
414 // XView must be allowed to choose its own sized buttons
415#ifdef __XVIEW__
416 largeButtonWidth = -1;
417 largeButtonHeight = -1;
418
419 smallButtonWidth = -1;
420 smallButtonHeight = -1;
421#endif
422
423 if (m_valueText)
424 return TRUE;
425
426 if (!panel)
427 return FALSE;
428
429 wxWindow *leftMostWindow = panel;
8710cf5c 430/*
e3a43801
JS
431 wxWindow *topMostWindow = panel;
432 wxWindow *rightMostWindow = panel;
8710cf5c 433*/
e3a43801
JS
434
435 wxSystemSettings settings;
436 wxFont guiFont = settings.GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
437
438#ifdef __WXMSW__
439 wxFont *boringFont = wxTheFontList->FindOrCreateFont(guiFont.GetPointSize(), wxMODERN, wxNORMAL, wxNORMAL, FALSE, "Courier New");
440#else
441 wxFont *boringFont = wxTheFontList->FindOrCreateFont(guiFont.GetPointSize(), wxTELETYPE, wxNORMAL, wxNORMAL);
442#endif
443
444 // May need to be changed in future to eliminate clashes with app.
445 // WHAT WAS THIS FOR?
446// panel->SetClientData((char *)this);
447
448 // These buttons are at the bottom of the window, but create them now
449 // so the constraints are evaluated in the correct order
450 if (m_buttonFlags & wxPROP_BUTTON_OK)
451 {
452 m_windowCloseButton = new wxButton(panel, wxID_OK, "OK",
453 wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
454 m_windowCloseButton->SetDefault();
455 m_windowCloseButton->SetFocus();
456 }
457 else if (m_buttonFlags & wxPROP_BUTTON_CLOSE)
458 {
459 m_windowCloseButton = new wxButton(panel, wxID_OK, "Close",
460 wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
461 }
462 if (m_buttonFlags & wxPROP_BUTTON_CANCEL)
463 {
464 m_windowCancelButton = new wxButton(panel, wxID_CANCEL, "Cancel",
465 wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
466 }
467 if (m_buttonFlags & wxPROP_BUTTON_HELP)
468 {
469 m_windowHelpButton = new wxButton(panel, wxID_HELP, "Help",
470 wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
471 }
472
473 if (m_windowCloseButton)
474 {
475 wxLayoutConstraints *c1 = new wxLayoutConstraints;
476
477 c1->left.SameAs (panel, wxLeft, 2);
478 c1->bottom.SameAs (panel, wxBottom, 2);
479 c1->width.AsIs();
480 c1->height.AsIs();
481 m_windowCloseButton->SetConstraints(c1);
482 leftMostWindow = m_windowCloseButton;
483 }
484 if (m_windowCancelButton)
485 {
486 wxLayoutConstraints *c2 = new wxLayoutConstraints;
487
488 c2->right.SameAs (panel, wxRight, 2);
489 c2->bottom.SameAs (panel, wxBottom, 2);
490 c2->width.AsIs();
491 c2->height.AsIs();
492 m_windowCancelButton->SetConstraints(c2);
493 leftMostWindow = m_windowCancelButton;
494 }
495 if (m_windowHelpButton)
496 {
497 wxLayoutConstraints *c2 = new wxLayoutConstraints;
498 if (leftMostWindow == panel)
499 c2->left.SameAs (panel, wxLeft, 2);
500 else
501 c2->left.RightOf (leftMostWindow, 2);
502
503 c2->bottom.SameAs (panel, wxBottom, 2);
504 c2->width.AsIs();
505 c2->height.AsIs();
506 m_windowHelpButton->SetConstraints(c2);
507 leftMostWindow = m_windowHelpButton;
508 }
509
510 if (m_buttonFlags & wxPROP_BUTTON_CHECK_CROSS)
511 {
512/*
513 if (!tickBitmap)
514 {
515#ifdef __WXMSW__
516 tickBitmap = new wxBitmap("tick_bmp", wxBITMAP_TYPE_RESOURCE);
517 crossBitmap = new wxBitmap("cross_bmp", wxBITMAP_TYPE_RESOURCE);
518 if (!tickBitmap || !crossBitmap || !tickBitmap->Ok() || !crossBitmap->Ok())
519 {
520 if (tickBitmap)
521 delete tickBitmap;
522 if (crossBitmap)
523 delete crossBitmap;
524 tickBitmap = NULL;
525 crossBitmap = NULL;
526 }
527#endif
528 }
529*/
530/*
531 if (tickBitmap && crossBitmap)
532 {
533 m_confirmButton = new wxBitmapButton(panel, wxID_PROP_CHECK, tickBitmap,
534 wxPoint(-1, -1), wxSize(smallButtonWidth-5, smallButtonHeight-5));
535 m_cancelButton = new wxBitmapButton(panel, wxID_PROP_CROSS, crossBitmap,
536 wxPoint(-1, -1), wxSize(smallButtonWidth-5, smallButtonHeight-5));
537 }
538 else
539*/
540 {
541 m_confirmButton = new wxButton(panel, wxID_PROP_CHECK, ":-)",
542 wxPoint(-1, -1), wxSize(smallButtonWidth, smallButtonHeight));
543 m_cancelButton = new wxButton(panel, wxID_PROP_CROSS, "X",
544 wxPoint(-1, -1), wxSize(smallButtonWidth, smallButtonHeight));
545 }
546
547 wxLayoutConstraints *c = new wxLayoutConstraints;
548 c->left.SameAs (panel, wxLeft, 2);
549/*
550 if (windowCloseButton)
551 c->top.Below (m_windowCloseButton, 2);
552 else
553*/
554 c->top.SameAs (panel, wxTop, 2);
555
556 c->width.AsIs();
557 c->height.AsIs();
558
559 m_cancelButton->SetConstraints(c);
560
561 c = new wxLayoutConstraints;
562 c->left.RightOf (m_cancelButton, 2);
563 c->top.SameAs (m_cancelButton, wxTop, 0);
564 c->width.AsIs();
565 c->height.AsIs();
566
567 m_confirmButton->SetConstraints(c);
568
569 m_cancelButton->Enable(FALSE);
570 m_confirmButton->Enable(FALSE);
571 }
572
573 if (m_buttonFlags & wxPROP_PULLDOWN)
574 {
575 m_editButton = new wxButton(panel, wxID_PROP_EDIT, "...",
576 wxPoint(-1, -1), wxSize(smallButtonWidth, smallButtonHeight));
577 m_editButton->Enable(FALSE);
578 wxLayoutConstraints *c = new wxLayoutConstraints;
579
580/*
581 if (m_windowCloseButton)
582 c->top.Below (m_windowCloseButton, 2);
583 else
584*/
585 c->top.SameAs (panel, wxTop, 2);
586
587 c->right.SameAs (panel, wxRight, 2);
588 c->width.AsIs();
589 c->height.AsIs();
590 m_editButton->SetConstraints(c);
591 }
592
593 m_valueText = new wxPropertyTextEdit(this, panel, wxID_PROP_TEXT, "", wxPoint(-1, -1), wxSize(-1, -1), wxPROCESS_ENTER);
594 m_valueText->Enable(FALSE);
595
596 wxLayoutConstraints *c = new wxLayoutConstraints;
597
598 if (m_cancelButton)
599 c->left.RightOf (m_confirmButton, 2);
600 else
601 c->left.SameAs (panel, wxLeft, 2);
602/*
603 if (m_windowCloseButton)
604 c->top.Below (m_windowCloseButton, 2);
605 else
606*/
607 c->top.SameAs (panel, wxTop, 2);
608
609 if (m_editButton)
610 c->right.LeftOf (m_editButton, 2);
611 else
612 c->right.SameAs (panel, wxRight, 2);
613 c->height.AsIs();
614
615 m_valueText->SetConstraints(c);
616
617 m_valueList = new wxListBox(panel, wxID_PROP_VALUE_SELECT, wxPoint(-1, -1), wxSize(-1, 60));
618 m_valueList->Show(FALSE);
619
620 c = new wxLayoutConstraints;
621
622 c->left.SameAs (panel, wxLeft, 2);
623 c->top.Below (m_valueText, 2);
624 c->right.SameAs (panel, wxRight, 2);
625 c->height.Absolute(60);
626
627 m_valueList->SetConstraints(c);
628
629 m_propertyScrollingList = new wxListBox(panel, wxID_PROP_SELECT,
630 wxPoint(-1, -1), wxSize(300, 300));
631 m_propertyScrollingList->SetFont(* boringFont);
632
633 c = new wxLayoutConstraints;
634
635 c->left.SameAs (panel, wxLeft, 2);
636
637 if (m_buttonFlags & wxPROP_DYNAMIC_VALUE_FIELD)
638 c->top.Below (m_valueText, 2);
639 else
640 c->top.Below (m_valueList, 2);
641
642 c->right.SameAs (panel, wxRight, 2);
643
644 if (m_windowCloseButton)
645 c->bottom.Above (m_windowCloseButton, -2);
646 else
647 c->bottom.SameAs (panel, wxBottom, 2);
648
649 m_propertyScrollingList->SetConstraints(c);
650
651 // Note: if this is called now, it causes a GPF.
652 // Why?
653// panel->Layout();
654
655 return TRUE;
656}
657
658void wxPropertyListView::ShowTextControl(bool show)
659{
660 if (m_valueText)
661 m_valueText->Show(show);
662}
663
664void wxPropertyListView::ShowListBoxControl(bool show)
665{
666 if (m_valueList)
667 {
668 m_valueList->Show(show);
669 if (m_buttonFlags & wxPROP_DYNAMIC_VALUE_FIELD)
670 {
671 wxLayoutConstraints *constraints = m_propertyScrollingList->GetConstraints();
672 if (constraints)
673 {
674 if (show)
675 {
676 constraints->top.Below(m_valueList, 2);
677 // Maintain back-pointer so when valueList is deleted,
678 // any reference to it from this window is removed.
679 m_valueList->AddConstraintReference(m_propertyScrollingList);
680 }
681 else
682 {
683 constraints->top.Below(m_valueText, 2);
684 m_valueText->AddConstraintReference(m_propertyScrollingList);
685 }
686 m_propertyWindow->Layout();
687 }
688 }
689 }
690}
691
692void wxPropertyListView::EnableCheck(bool show)
693{
694 if (m_confirmButton)
695 m_confirmButton->Enable(show);
696}
697
698void wxPropertyListView::EnableCross(bool show)
699{
700 if (m_cancelButton)
701 m_cancelButton->Enable(show);
702}
703
704bool wxPropertyListView::OnClose(void)
705{
706 // Retrieve the value if any
707 wxCommandEvent event;
708 OnCheck(event);
709
710 delete this;
711 return TRUE;
712}
713
714void wxPropertyListView::OnValueListSelect(wxCommandEvent& WXUNUSED(event))
715{
716 if (m_currentProperty && m_currentValidator)
717 {
718 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
719 return;
720
721 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
722
723 listValidator->OnValueListSelect(m_currentProperty, this, m_propertyWindow);
724 }
725}
726
727void wxPropertyListView::OnOk(wxCommandEvent& event)
728{
729 // Retrieve the value if any
730 OnCheck(event);
731
732 m_managedWindow->Close(TRUE);
733}
734
735void wxPropertyListView::OnCancel(wxCommandEvent& WXUNUSED(event))
736{
737// SetReturnCode(wxID_CANCEL);
738 m_managedWindow->Close(TRUE);
739 sm_dialogCancelled = TRUE;
740}
741
742void wxPropertyListView::OnHelp(wxCommandEvent& WXUNUSED(event))
743{
744}
745
746void wxPropertyListView::OnCheck(wxCommandEvent& WXUNUSED(event))
747{
748 if (m_currentProperty)
749 {
750 RetrieveProperty(m_currentProperty);
751 }
752}
753
754void wxPropertyListView::OnCross(wxCommandEvent& WXUNUSED(event))
755{
756 if (m_currentProperty && m_currentValidator)
757 {
758 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
759 return;
760
761 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
762
763 // Revert to old value
764 listValidator->OnDisplayValue(m_currentProperty, this, m_propertyWindow);
765 }
766}
767
768void wxPropertyListView::OnPropertyDoubleClick(wxCommandEvent& WXUNUSED(event))
769{
770 if (m_currentProperty && m_currentValidator)
771 {
772 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
773 return;
774
775 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
776
777 // Revert to old value
778 listValidator->OnDoubleClick(m_currentProperty, this, m_propertyWindow);
779 }
780}
781
782void wxPropertyListView::OnEdit(wxCommandEvent& WXUNUSED(event))
783{
784 if (m_currentProperty && m_currentValidator)
785 {
786 if (!m_currentValidator->IsKindOf(CLASSINFO(wxPropertyListValidator)))
787 return;
788
789 wxPropertyListValidator *listValidator = (wxPropertyListValidator *)m_currentValidator;
790
791 listValidator->OnEdit(m_currentProperty, this, m_propertyWindow);
792 }
793}
794
795void wxPropertyListView::OnText(wxCommandEvent& event)
796{
797 if (event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER)
798 {
799 OnCheck(event);
800 }
801}
802
803/*
804 * Property dialog box
805 */
806
807IMPLEMENT_CLASS(wxPropertyListDialog, wxDialog)
808
809BEGIN_EVENT_TABLE(wxPropertyListDialog, wxDialog)
810 EVT_BUTTON(wxID_CANCEL, wxPropertyListDialog::OnCancel)
e3065973 811 EVT_CLOSE(wxPropertyListDialog::OnCloseWindow)
e3a43801
JS
812END_EVENT_TABLE()
813
814wxPropertyListDialog::wxPropertyListDialog(wxPropertyListView *v, wxWindow *parent,
815 const wxString& title, const wxPoint& pos,
816 const wxSize& size, long style, const wxString& name):
817 wxDialog(parent, -1, title, pos, size, style, name)
818{
819 m_view = v;
820 m_view->AssociatePanel( ((wxPanel*)this) );
821 m_view->SetManagedWindow(this);
822 SetAutoLayout(TRUE);
823}
824
e3065973 825void wxPropertyListDialog::OnCloseWindow(wxCloseEvent& event)
e3a43801
JS
826{
827 if (m_view)
828 {
829 SetReturnCode(wxID_CANCEL);
830 m_view->OnClose();
831 m_view = NULL;
e3065973 832 this->Destroy();
e3a43801
JS
833 }
834 else
e3065973
JS
835 {
836 event.Veto();
837 }
e3a43801
JS
838}
839
840void wxPropertyListDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
841{
842 SetReturnCode(wxID_CANCEL);
843 this->Close();
844}
845
8710cf5c 846void wxPropertyListDialog::OnDefaultAction(wxControl *WXUNUSED(item))
e3a43801
JS
847{
848/*
849 if (item == m_view->GetPropertyScrollingList())
850 view->OnDoubleClick();
851*/
852}
853
854// Extend event processing to search the view's event table
855bool wxPropertyListDialog::ProcessEvent(wxEvent& event)
856{
857 if ( !m_view || ! m_view->ProcessEvent(event) )
858 return wxEvtHandler::ProcessEvent(event);
859 else
860 return TRUE;
861}
862
863/*
864 * Property panel
865 */
866
867IMPLEMENT_CLASS(wxPropertyListPanel, wxPanel)
868
869BEGIN_EVENT_TABLE(wxPropertyListPanel, wxPanel)
870 EVT_SIZE(wxPropertyListPanel::OnSize)
871END_EVENT_TABLE()
872
873wxPropertyListPanel::~wxPropertyListPanel()
874{
875}
876
8710cf5c 877void wxPropertyListPanel::OnDefaultAction(wxControl *WXUNUSED(item))
e3a43801
JS
878{
879/*
880 if (item == view->GetPropertyScrollingList())
881 view->OnDoubleClick();
882*/
883}
884
885// Extend event processing to search the view's event table
886bool wxPropertyListPanel::ProcessEvent(wxEvent& event)
887{
888 if ( !m_view || ! m_view->ProcessEvent(event) )
889 return wxEvtHandler::ProcessEvent(event);
890 else
891 return TRUE;
892}
893
894void wxPropertyListPanel::OnSize(wxSizeEvent& WXUNUSED(event))
895{
896 Layout();
897}
898
899/*
900 * Property frame
901 */
902
903IMPLEMENT_CLASS(wxPropertyListFrame, wxFrame)
904
e3065973
JS
905BEGIN_EVENT_TABLE(wxPropertyListFrame, wxFrame)
906 EVT_CLOSE(wxPropertyListFrame::OnCloseWindow)
907END_EVENT_TABLE()
908
909void wxPropertyListFrame::OnCloseWindow(wxCloseEvent& event)
e3a43801
JS
910{
911 if (m_view)
912 {
913 if (m_propertyPanel)
914 m_propertyPanel->SetView(NULL);
915 m_view->OnClose();
916 m_view = NULL;
e3065973 917 this->Destroy();
e3a43801
JS
918 }
919 else
e3065973
JS
920 {
921 event.Veto();
922 }
e3a43801
JS
923}
924
925wxPropertyListPanel *wxPropertyListFrame::OnCreatePanel(wxFrame *parent, wxPropertyListView *v)
926{
927 return new wxPropertyListPanel(v, parent);
928}
929
930bool wxPropertyListFrame::Initialize(void)
931{
932 m_propertyPanel = OnCreatePanel(this, m_view);
933 if (m_propertyPanel)
934 {
935 m_view->AssociatePanel(m_propertyPanel);
936 m_view->SetManagedWindow(this);
937 m_propertyPanel->SetAutoLayout(TRUE);
938 return TRUE;
939 }
940 else
941 return FALSE;
942}
943
944 /*
945 * Property list specific validator
946 */
947
948IMPLEMENT_ABSTRACT_CLASS(wxPropertyListValidator, wxPropertyValidator)
949
950bool wxPropertyListValidator::OnSelect(bool select, wxProperty *property, wxPropertyListView *view, wxWindow *parentWindow)
951{
952// view->GetValueText()->Show(TRUE);
953 if (select)
954 OnDisplayValue(property, view, parentWindow);
955
956 return TRUE;
957}
958
8710cf5c 959bool wxPropertyListValidator::OnValueListSelect(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
960{
961 wxString s(view->GetValueList()->GetStringSelection());
962 if (s != "")
963 {
964 view->GetValueText()->SetValue(s);
965 view->RetrieveProperty(property);
966 }
967 return TRUE;
968}
969
8710cf5c 970bool wxPropertyListValidator::OnDisplayValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
971{
972// view->GetValueText()->Show(TRUE);
973 wxString str(property->GetValue().GetStringRepresentation());
974
975 view->GetValueText()->SetValue(str);
976 return TRUE;
977}
978
979// Called when TICK is pressed or focus is lost or view wants to update
980// the property list.
981// Does the transferance from the property editing area to the property itself
8710cf5c 982bool wxPropertyListValidator::OnRetrieveValue(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
983{
984 if (!view->GetValueText())
985 return FALSE;
986 return FALSE;
987}
988
8710cf5c 989void wxPropertyListValidator::OnEdit(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
990{
991 if (view->GetDetailedEditing())
992 view->EndDetailedEditing();
993 else
994 view->BeginDetailedEditing();
995}
996
8710cf5c 997bool wxPropertyListValidator::OnClearControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
998{
999 if (view->GetConfirmButton())
1000 view->GetConfirmButton()->Enable(FALSE);
1001 if (view->GetCancelButton())
1002 view->GetCancelButton()->Enable(FALSE);
1003 if (view->GetEditButton())
1004 view->GetEditButton()->Enable(FALSE);
1005 return TRUE;
1006}
1007
1008/*
1009 * Default validators
1010 */
1011
1012IMPLEMENT_DYNAMIC_CLASS(wxRealListValidator, wxPropertyListValidator)
1013
1014///
1015/// Real number validator
1016///
8710cf5c 1017bool wxRealListValidator::OnCheckValue(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *parentWindow)
e3a43801
JS
1018{
1019 if (m_realMin == 0.0 && m_realMax == 0.0)
1020 return TRUE;
1021
1022 if (!view->GetValueText())
1023 return FALSE;
1024 wxString value(view->GetValueText()->GetValue());
1025
1026 float val = 0.0;
1027 if (!StringToFloat(WXSTRINGCAST value, &val))
1028 {
1029 char buf[200];
1030 sprintf(buf, "Value %s is not a valid real number!", value.GetData());
1031 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
1032 return FALSE;
1033 }
1034
1035 if (val < m_realMin || val > m_realMax)
1036 {
1037 char buf[200];
1038 sprintf(buf, "Value must be a real number between %.2f and %.2f!", m_realMin, m_realMax);
1039 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
1040 return FALSE;
1041 }
1042 return TRUE;
1043}
1044
1045// Called when TICK is pressed or focus is lost or view wants to update
1046// the property list.
1047// Does the transferance from the property editing area to the property itself
8710cf5c 1048bool wxRealListValidator::OnRetrieveValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1049{
1050 if (!view->GetValueText())
1051 return FALSE;
1052
1053 if (strlen(view->GetValueText()->GetValue()) == 0)
1054 return FALSE;
1055
1056 wxString value(view->GetValueText()->GetValue());
1057 float f = (float)atof(value.GetData());
1058 property->GetValue() = f;
1059 return TRUE;
1060}
1061
8710cf5c 1062bool wxRealListValidator::OnPrepareControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1063{
1064 if (view->GetConfirmButton())
1065 view->GetConfirmButton()->Enable(TRUE);
1066 if (view->GetCancelButton())
1067 view->GetCancelButton()->Enable(TRUE);
1068 if (view->GetEditButton())
1069 view->GetEditButton()->Enable(FALSE);
1070 if (view->GetValueText())
1071 view->GetValueText()->Enable(TRUE);
1072 return TRUE;
1073}
1074
1075///
1076/// Integer validator
1077///
1078IMPLEMENT_DYNAMIC_CLASS(wxIntegerListValidator, wxPropertyListValidator)
1079
8710cf5c 1080bool wxIntegerListValidator::OnCheckValue(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *parentWindow)
e3a43801
JS
1081{
1082 if (m_integerMin == 0 && m_integerMax == 0)
1083 return TRUE;
1084
1085 if (!view->GetValueText())
1086 return FALSE;
1087 wxString value(view->GetValueText()->GetValue());
1088
1089 long val = 0;
1090 if (!StringToLong(WXSTRINGCAST value, &val))
1091 {
1092 char buf[200];
1093 sprintf(buf, "Value %s is not a valid integer!", value.GetData());
1094 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
1095 return FALSE;
1096 }
1097 if (val < m_integerMin || val > m_integerMax)
1098 {
1099 char buf[200];
1100 sprintf(buf, "Value must be an integer between %ld and %ld!", m_integerMin, m_integerMax);
1101 wxMessageBox(buf, "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
1102 return FALSE;
1103 }
1104 return TRUE;
1105}
1106
1107// Called when TICK is pressed or focus is lost or view wants to update
1108// the property list.
1109// Does the transferance from the property editing area to the property itself
8710cf5c 1110bool wxIntegerListValidator::OnRetrieveValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1111{
1112 if (!view->GetValueText())
1113 return FALSE;
1114
1115 if (strlen(view->GetValueText()->GetValue()) == 0)
1116 return FALSE;
1117
1118 wxString value(view->GetValueText()->GetValue());
1119 long val = (long)atoi(value.GetData());
1120 property->GetValue() = (long)val;
1121 return TRUE;
1122}
1123
8710cf5c 1124bool wxIntegerListValidator::OnPrepareControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1125{
1126 if (view->GetConfirmButton())
1127 view->GetConfirmButton()->Enable(TRUE);
1128 if (view->GetCancelButton())
1129 view->GetCancelButton()->Enable(TRUE);
1130 if (view->GetEditButton())
1131 view->GetEditButton()->Enable(FALSE);
1132 if (view->GetValueText())
1133 view->GetValueText()->Enable(TRUE);
1134 return TRUE;
1135}
1136
1137///
1138/// boolean validator
1139///
1140IMPLEMENT_DYNAMIC_CLASS(wxBoolListValidator, wxPropertyListValidator)
1141
8710cf5c 1142bool wxBoolListValidator::OnCheckValue(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *parentWindow)
e3a43801
JS
1143{
1144 if (!view->GetValueText())
1145 return FALSE;
1146 wxString value(view->GetValueText()->GetValue());
1147 if (value != "True" && value != "False")
1148 {
1149 wxMessageBox("Value must be True or False!", "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
1150 return FALSE;
1151 }
1152 return TRUE;
1153}
1154
1155// Called when TICK is pressed or focus is lost or view wants to update
1156// the property list.
1157// Does the transferance from the property editing area to the property itself
8710cf5c 1158bool wxBoolListValidator::OnRetrieveValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1159{
1160 if (!view->GetValueText())
1161 return FALSE;
1162
1163 if (strlen(view->GetValueText()->GetValue()) == 0)
1164 return FALSE;
1165
1166 wxString value(view->GetValueText()->GetValue());
1167 bool boolValue = FALSE;
1168 if (value == "True")
1169 boolValue = TRUE;
1170 else
1171 boolValue = FALSE;
1172 property->GetValue() = (bool)boolValue;
1173 return TRUE;
1174}
1175
8710cf5c 1176bool wxBoolListValidator::OnDisplayValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1177{
1178 if (!view->GetValueText())
1179 return FALSE;
1180 wxString str(property->GetValue().GetStringRepresentation());
1181
1182 view->GetValueText()->SetValue(str);
1183
1184 if (view->GetValueList()->IsShown())
1185 {
1186 view->GetValueList()->SetStringSelection(str);
1187 }
1188 return TRUE;
1189}
1190
8710cf5c 1191bool wxBoolListValidator::OnPrepareControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1192{
1193 if (view->GetConfirmButton())
1194 view->GetConfirmButton()->Enable(FALSE);
1195 if (view->GetCancelButton())
1196 view->GetCancelButton()->Enable(FALSE);
1197 if (view->GetEditButton())
1198 view->GetEditButton()->Enable(TRUE);
1199 if (view->GetValueText())
1200 view->GetValueText()->Enable(FALSE);
1201 return TRUE;
1202}
1203
8710cf5c 1204bool wxBoolListValidator::OnPrepareDetailControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1205{
1206 if (view->GetValueList())
1207 {
1208 view->ShowListBoxControl(TRUE);
1209 view->GetValueList()->Enable(TRUE);
1210
1211 view->GetValueList()->Append("True");
1212 view->GetValueList()->Append("False");
1213 char *currentString = copystring(view->GetValueText()->GetValue());
1214 view->GetValueList()->SetStringSelection(currentString);
1215 delete[] currentString;
1216 }
1217 return TRUE;
1218}
1219
8710cf5c 1220bool wxBoolListValidator::OnClearDetailControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1221{
1222 if (view->GetValueList())
1223 {
1224 view->GetValueList()->Clear();
1225 view->ShowListBoxControl(FALSE);
1226 view->GetValueList()->Enable(FALSE);
1227 }
1228 return TRUE;
1229}
1230
1231// Called when the property is double clicked. Extra functionality can be provided,
1232// cycling through possible values.
8710cf5c 1233bool wxBoolListValidator::OnDoubleClick(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1234{
1235 if (!view->GetValueText())
1236 return FALSE;
1237 if (property->GetValue().BoolValue())
1238 property->GetValue() = (bool)FALSE;
1239 else
1240 property->GetValue() = (bool)TRUE;
1241 view->DisplayProperty(property);
1242 view->UpdatePropertyDisplayInList(property);
1243 view->OnPropertyChanged(property);
1244 return TRUE;
1245}
1246
1247///
1248/// String validator
1249///
1250IMPLEMENT_DYNAMIC_CLASS(wxStringListValidator, wxPropertyListValidator)
1251
1252wxStringListValidator::wxStringListValidator(wxStringList *list, long flags):
1253 wxPropertyListValidator(flags)
1254{
1255 m_strings = list;
1256 // If no constraint, we just allow the string to be edited.
1257 if (!m_strings && ((m_validatorFlags & wxPROP_ALLOW_TEXT_EDITING) == 0))
1258 m_validatorFlags |= wxPROP_ALLOW_TEXT_EDITING;
1259}
1260
8710cf5c 1261bool wxStringListValidator::OnCheckValue(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *parentWindow)
e3a43801
JS
1262{
1263 if (!m_strings)
1264 return TRUE;
1265
1266 if (!view->GetValueText())
1267 return FALSE;
1268 wxString value(view->GetValueText()->GetValue());
1269
1270 if (!m_strings->Member(value.GetData()))
1271 {
1272 wxString s("Value ");
1273 s += value.GetData();
1274 s += " is not valid.";
1275 wxMessageBox(s.GetData(), "Property value error", wxOK | wxICON_EXCLAMATION, parentWindow);
1276 return FALSE;
1277 }
1278 return TRUE;
1279}
1280
1281// Called when TICK is pressed or focus is lost or view wants to update
1282// the property list.
1283// Does the transferance from the property editing area to the property itself
8710cf5c 1284bool wxStringListValidator::OnRetrieveValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1285{
1286 if (!view->GetValueText())
1287 return FALSE;
1288 wxString value(view->GetValueText()->GetValue());
1289 property->GetValue() = value ;
1290 return TRUE;
1291}
1292
1293// Called when TICK is pressed or focus is lost or view wants to update
1294// the property list.
1295// Does the transferance from the property editing area to the property itself
8710cf5c 1296bool wxStringListValidator::OnDisplayValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1297{
1298 if (!view->GetValueText())
1299 return FALSE;
1300 wxString str(property->GetValue().GetStringRepresentation());
1301 view->GetValueText()->SetValue(str);
1302 if (m_strings && view->GetValueList() && view->GetValueList()->IsShown() && view->GetValueList()->Number() > 0)
1303 {
1304 view->GetValueList()->SetStringSelection(str);
1305 }
1306 return TRUE;
1307}
1308
8710cf5c 1309bool wxStringListValidator::OnPrepareControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1310{
1311 // Unconstrained
1312 if (!m_strings)
1313 {
1314 if (view->GetEditButton())
1315 view->GetEditButton()->Enable(FALSE);
1316 if (view->GetConfirmButton())
1317 view->GetConfirmButton()->Enable(TRUE);
1318 if (view->GetCancelButton())
1319 view->GetCancelButton()->Enable(TRUE);
1320 if (view->GetValueText())
1321 view->GetValueText()->Enable(TRUE);
1322 return TRUE;
1323 }
1324
1325 // Constrained
1326 if (view->GetValueText())
1327 view->GetValueText()->Enable(FALSE);
1328
1329 if (view->GetEditButton())
1330 view->GetEditButton()->Enable(TRUE);
1331
1332 if (view->GetConfirmButton())
1333 view->GetConfirmButton()->Enable(FALSE);
1334 if (view->GetCancelButton())
1335 view->GetCancelButton()->Enable(FALSE);
1336 return TRUE;
1337}
1338
8710cf5c 1339bool wxStringListValidator::OnPrepareDetailControls(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1340{
1341 if (view->GetValueList())
1342 {
1343 view->ShowListBoxControl(TRUE);
1344 view->GetValueList()->Enable(TRUE);
1345 wxNode *node = m_strings->First();
1346 while (node)
1347 {
1348 char *s = (char *)node->Data();
1349 view->GetValueList()->Append(s);
1350 node = node->Next();
1351 }
1352 char *currentString = property->GetValue().StringValue();
1353 view->GetValueList()->SetStringSelection(currentString);
1354 }
1355 return TRUE;
1356}
1357
8710cf5c 1358bool wxStringListValidator::OnClearDetailControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1359{
1360 if (!m_strings)
1361 {
1362 return TRUE;
1363 }
1364
1365 if (view->GetValueList())
1366 {
1367 view->GetValueList()->Clear();
1368 view->ShowListBoxControl(FALSE);
1369 view->GetValueList()->Enable(FALSE);
1370 }
1371 return TRUE;
1372}
1373
1374// Called when the property is double clicked. Extra functionality can be provided,
1375// cycling through possible values.
8710cf5c 1376bool wxStringListValidator::OnDoubleClick(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1377{
1378 if (!view->GetValueText())
1379 return FALSE;
1380 if (!m_strings)
1381 return FALSE;
1382
1383 wxNode *node = m_strings->First();
1384 char *currentString = property->GetValue().StringValue();
1385 while (node)
1386 {
1387 char *s = (char *)node->Data();
1388 if (strcmp(s, currentString) == 0)
1389 {
1390 char *nextString = NULL;
1391 if (node->Next())
1392 nextString = (char *)node->Next()->Data();
1393 else
1394 nextString = (char *)m_strings->First()->Data();
1395 property->GetValue() = wxString(nextString);
1396 view->DisplayProperty(property);
1397 view->UpdatePropertyDisplayInList(property);
1398 view->OnPropertyChanged(property);
1399 return TRUE;
1400 }
1401 else node = node->Next();
1402 }
1403 return TRUE;
1404}
1405
1406///
1407/// Filename validator
1408///
1409IMPLEMENT_DYNAMIC_CLASS(wxFilenameListValidator, wxPropertyListValidator)
1410
1411wxFilenameListValidator::wxFilenameListValidator(wxString message , wxString wildcard, long flags):
1412 wxPropertyListValidator(flags), m_filenameWildCard(wildcard), m_filenameMessage(message)
1413{
1414}
1415
1416wxFilenameListValidator::~wxFilenameListValidator(void)
1417{
1418}
1419
8710cf5c 1420bool wxFilenameListValidator::OnCheckValue(wxProperty *WXUNUSED(property), wxPropertyListView *WXUNUSED(view), wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1421{
1422 return TRUE;
1423}
1424
1425// Called when TICK is pressed or focus is lost or view wants to update
1426// the property list.
1427// Does the transferance from the property editing area to the property itself
8710cf5c 1428bool wxFilenameListValidator::OnRetrieveValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1429{
1430 if (!view->GetValueText())
1431 return FALSE;
1432 wxString value(view->GetValueText()->GetValue());
1433 property->GetValue() = value ;
1434 return TRUE;
1435}
1436
1437// Called when TICK is pressed or focus is lost or view wants to update
1438// the property list.
1439// Does the transferance from the property editing area to the property itself
8710cf5c 1440bool wxFilenameListValidator::OnDisplayValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1441{
1442 if (!view->GetValueText())
1443 return FALSE;
1444 wxString str(property->GetValue().GetStringRepresentation());
1445 view->GetValueText()->SetValue(str);
1446 return TRUE;
1447}
1448
1449// Called when the property is double clicked. Extra functionality can be provided,
1450// cycling through possible values.
1451bool wxFilenameListValidator::OnDoubleClick(wxProperty *property, wxPropertyListView *view, wxWindow *parentWindow)
1452{
1453 if (!view->GetValueText())
1454 return FALSE;
1455 OnEdit(property, view, parentWindow);
1456 return TRUE;
1457}
1458
8710cf5c 1459bool wxFilenameListValidator::OnPrepareControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1460{
1461 if (view->GetConfirmButton())
1462 view->GetConfirmButton()->Enable(TRUE);
1463 if (view->GetCancelButton())
1464 view->GetCancelButton()->Enable(TRUE);
1465 if (view->GetEditButton())
1466 view->GetEditButton()->Enable(TRUE);
1467 if (view->GetValueText())
1468 view->GetValueText()->Enable((GetFlags() & wxPROP_ALLOW_TEXT_EDITING) == wxPROP_ALLOW_TEXT_EDITING);
1469 return TRUE;
1470}
1471
1472void wxFilenameListValidator::OnEdit(wxProperty *property, wxPropertyListView *view, wxWindow *parentWindow)
1473{
1474 if (!view->GetValueText())
1475 return;
1476
227869da 1477 wxString s = wxFileSelector(
e3a43801
JS
1478 m_filenameMessage.GetData(),
1479 wxPathOnly(property->GetValue().StringValue()),
1480 wxFileNameFromPath(property->GetValue().StringValue()),
1481 NULL,
1482 m_filenameWildCard.GetData(),
1483 0,
1484 parentWindow);
227869da 1485 if (s != "")
e3a43801 1486 {
227869da 1487 property->GetValue() = s;
e3a43801
JS
1488 view->DisplayProperty(property);
1489 view->UpdatePropertyDisplayInList(property);
1490 view->OnPropertyChanged(property);
1491 }
1492}
1493
1494///
1495/// Colour validator
1496///
1497IMPLEMENT_DYNAMIC_CLASS(wxColourListValidator, wxPropertyListValidator)
1498
1499wxColourListValidator::wxColourListValidator(long flags):
1500 wxPropertyListValidator(flags)
1501{
1502}
1503
1504wxColourListValidator::~wxColourListValidator(void)
1505{
1506}
1507
8710cf5c 1508bool wxColourListValidator::OnCheckValue(wxProperty *WXUNUSED(property), wxPropertyListView *WXUNUSED(view), wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1509{
1510 return TRUE;
1511}
1512
1513// Called when TICK is pressed or focus is lost or view wants to update
1514// the property list.
1515// Does the transferance from the property editing area to the property itself
8710cf5c 1516bool wxColourListValidator::OnRetrieveValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1517{
1518 if (!view->GetValueText())
1519 return FALSE;
1520 wxString value(view->GetValueText()->GetValue());
1521
1522 property->GetValue() = value ;
1523 return TRUE;
1524}
1525
1526// Called when TICK is pressed or focus is lost or view wants to update
1527// the property list.
1528// Does the transferance from the property editing area to the property itself
8710cf5c 1529bool wxColourListValidator::OnDisplayValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1530{
1531 if (!view->GetValueText())
1532 return FALSE;
1533 wxString str(property->GetValue().GetStringRepresentation());
1534 view->GetValueText()->SetValue(str);
1535 return TRUE;
1536}
1537
1538// Called when the property is double clicked. Extra functionality can be provided,
1539// cycling through possible values.
1540bool wxColourListValidator::OnDoubleClick(wxProperty *property, wxPropertyListView *view, wxWindow *parentWindow)
1541{
1542 if (!view->GetValueText())
1543 return FALSE;
1544 OnEdit(property, view, parentWindow);
1545 return TRUE;
1546}
1547
8710cf5c 1548bool wxColourListValidator::OnPrepareControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1549{
1550 if (view->GetConfirmButton())
1551 view->GetConfirmButton()->Enable(TRUE);
1552 if (view->GetCancelButton())
1553 view->GetCancelButton()->Enable(TRUE);
1554 if (view->GetEditButton())
1555 view->GetEditButton()->Enable(TRUE);
1556 if (view->GetValueText())
1557 view->GetValueText()->Enable((GetFlags() & wxPROP_ALLOW_TEXT_EDITING) == wxPROP_ALLOW_TEXT_EDITING);
1558 return TRUE;
1559}
1560
1561void wxColourListValidator::OnEdit(wxProperty *property, wxPropertyListView *view, wxWindow *parentWindow)
1562{
1563 if (!view->GetValueText())
1564 return;
1565
1566 char *s = property->GetValue().StringValue();
1567 int r = 0;
1568 int g = 0;
1569 int b = 0;
1570 if (s)
1571 {
1572 r = wxHexToDec(s);
1573 g = wxHexToDec(s+2);
1574 b = wxHexToDec(s+4);
1575 }
1576
1577 wxColour col(r,g,b);
1578
1579 wxColourData data;
1580 data.SetChooseFull(TRUE);
1581 data.SetColour(col);
1582
1583 for (int i = 0; i < 16; i++)
1584 {
1585 wxColour colour(i*16, i*16, i*16);
1586 data.SetCustomColour(i, colour);
1587 }
1588
1589 wxColourDialog dialog(parentWindow, &data);
1590 if (dialog.ShowModal() != wxID_CANCEL)
1591 {
1592 wxColourData retData = dialog.GetColourData();
1593 col = retData.GetColour();
1594
1595 char buf[7];
1596 wxDecToHex(col.Red(), buf);
1597 wxDecToHex(col.Green(), buf+2);
1598 wxDecToHex(col.Blue(), buf+4);
1599
1600 property->GetValue() = wxString(buf);
1601 view->DisplayProperty(property);
1602 view->UpdatePropertyDisplayInList(property);
1603 view->OnPropertyChanged(property);
1604 }
1605}
1606
1607///
1608/// List of strings validator. For this we need more user interface than
1609/// we get with a property list; so create a new dialog for editing the list.
1610///
1611IMPLEMENT_DYNAMIC_CLASS(wxListOfStringsListValidator, wxPropertyListValidator)
1612
1613wxListOfStringsListValidator::wxListOfStringsListValidator(long flags):
1614 wxPropertyListValidator(flags)
1615{
1616}
1617
8710cf5c 1618bool wxListOfStringsListValidator::OnCheckValue(wxProperty *WXUNUSED(property), wxPropertyListView *WXUNUSED(view), wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1619{
1620 // No constraints for an arbitrary, user-editable list of strings.
1621 return TRUE;
1622}
1623
1624// Called when TICK is pressed or focus is lost or view wants to update
1625// the property list.
1626// Does the transferance from the property editing area to the property itself.
1627// In this case, the user cannot directly edit the string list.
8710cf5c 1628bool wxListOfStringsListValidator::OnRetrieveValue(wxProperty *WXUNUSED(property), wxPropertyListView *WXUNUSED(view), wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1629{
1630 return TRUE;
1631}
1632
8710cf5c 1633bool wxListOfStringsListValidator::OnDisplayValue(wxProperty *property, wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1634{
1635 if (!view->GetValueText())
1636 return FALSE;
1637 wxString str(property->GetValue().GetStringRepresentation());
1638 view->GetValueText()->SetValue(str);
1639 return TRUE;
1640}
1641
8710cf5c 1642bool wxListOfStringsListValidator::OnPrepareControls(wxProperty *WXUNUSED(property), wxPropertyListView *view, wxWindow *WXUNUSED(parentWindow))
e3a43801
JS
1643{
1644 if (view->GetEditButton())
1645 view->GetEditButton()->Enable(TRUE);
1646 if (view->GetValueText())
1647 view->GetValueText()->Enable(FALSE);
1648
1649 if (view->GetConfirmButton())
1650 view->GetConfirmButton()->Enable(FALSE);
1651 if (view->GetCancelButton())
1652 view->GetCancelButton()->Enable(FALSE);
1653 return TRUE;
1654}
1655
1656// Called when the property is double clicked. Extra functionality can be provided,
1657// cycling through possible values.
1658bool wxListOfStringsListValidator::OnDoubleClick(wxProperty *property, wxPropertyListView *view, wxWindow *parentWindow)
1659{
1660 OnEdit(property, view, parentWindow);
1661 return TRUE;
1662}
1663
1664void wxListOfStringsListValidator::OnEdit(wxProperty *property, wxPropertyListView *view, wxWindow *parentWindow)
1665{
1666 // Convert property value to a list of strings for editing
1667 wxStringList *stringList = new wxStringList;
1668
1669 wxPropertyValue *expr = property->GetValue().GetFirst();
1670 while (expr)
1671 {
1672 char *s = expr->StringValue();
1673 if (s)
1674 stringList->Add(s);
1675 expr = expr->GetNext();
1676 }
1677
1678 wxString title("Editing ");
1679 title += property->GetName();
1680
1681 if (EditStringList(parentWindow, stringList, title.GetData()))
1682 {
1683 wxPropertyValue& oldValue = property->GetValue();
1684 oldValue.ClearList();
1685 wxNode *node = stringList->First();
1686 while (node)
1687 {
1688 char *s = (char *)node->Data();
1689 oldValue.Append(new wxPropertyValue(s));
1690
1691 node = node->Next();
1692 }
1693
1694 view->DisplayProperty(property);
1695 view->UpdatePropertyDisplayInList(property);
1696 view->OnPropertyChanged(property);
1697 }
1698 delete stringList;
1699}
1700
1701class wxPropertyStringListEditorDialog: public wxDialog
1702{
1703 public:
1704 wxPropertyStringListEditorDialog(wxWindow *parent, const wxString& title,
1705 const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
1706 long windowStyle = wxDEFAULT_DIALOG_STYLE, const wxString& name = "stringEditorDialogBox"):
1707 wxDialog(parent, -1, title, pos, size, windowStyle, name)
1708 {
1709 m_stringList = NULL;
1710 m_stringText = NULL;
1711 m_listBox = NULL;
1712 sm_dialogCancelled = FALSE;
1713 m_currentSelection = -1;
1714 }
1715 ~wxPropertyStringListEditorDialog(void) {}
3b1e466c 1716 void OnCloseWindow(wxCloseEvent& event);
e3a43801
JS
1717 void SaveCurrentSelection(void);
1718 void ShowCurrentSelection(void);
1719
1720 void OnOK(wxCommandEvent& event);
1721 void OnCancel(wxCommandEvent& event);
1722 void OnAdd(wxCommandEvent& event);
1723 void OnDelete(wxCommandEvent& event);
1724 void OnStrings(wxCommandEvent& event);
1725 void OnText(wxCommandEvent& event);
1726
1727public:
1728 wxStringList* m_stringList;
1729 wxListBox* m_listBox;
1730 wxTextCtrl* m_stringText;
1731 static bool sm_dialogCancelled;
1732 int m_currentSelection;
1733DECLARE_EVENT_TABLE()
1734};
1735
1736#define wxID_PROP_SL_ADD 3000
1737#define wxID_PROP_SL_DELETE 3001
1738#define wxID_PROP_SL_STRINGS 3002
1739#define wxID_PROP_SL_TEXT 3003
1740
1741BEGIN_EVENT_TABLE(wxPropertyStringListEditorDialog, wxDialog)
1742 EVT_BUTTON(wxID_OK, wxPropertyStringListEditorDialog::OnOK)
1743 EVT_BUTTON(wxID_CANCEL, wxPropertyStringListEditorDialog::OnCancel)
1744 EVT_BUTTON(wxID_PROP_SL_ADD, wxPropertyStringListEditorDialog::OnAdd)
1745 EVT_BUTTON(wxID_PROP_SL_DELETE, wxPropertyStringListEditorDialog::OnDelete)
1746 EVT_LISTBOX(wxID_PROP_SL_STRINGS, wxPropertyStringListEditorDialog::OnStrings)
1747 EVT_TEXT_ENTER(wxID_PROP_SL_TEXT, wxPropertyStringListEditorDialog::OnText)
3b1e466c 1748 EVT_CLOSE(wxPropertyStringListEditorDialog::OnCloseWindow)
e3a43801
JS
1749END_EVENT_TABLE()
1750
1751class wxPropertyStringListEditorText: public wxTextCtrl
1752{
1753 public:
1754 wxPropertyStringListEditorText(wxWindow *parent, wxWindowID id, const wxString& val,
1755 const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
1756 long windowStyle = 0, const wxString& name = "text"):
1757 wxTextCtrl(parent, id, val, pos, size, windowStyle, wxDefaultValidator, name)
1758 {
1759 }
1760 void OnKillFocus(void)
1761 {
1762 wxPropertyStringListEditorDialog *dialog = (wxPropertyStringListEditorDialog *)GetParent();
1763 dialog->SaveCurrentSelection();
1764 }
1765};
1766
1767bool wxPropertyStringListEditorDialog::sm_dialogCancelled = FALSE;
1768
1769// Edit the string list.
1770bool wxListOfStringsListValidator::EditStringList(wxWindow *parent, wxStringList *stringList, const char *title)
1771{
1772 int largeButtonWidth = 60;
1773 int largeButtonHeight = 25;
1774
1775 wxBeginBusyCursor();
1776 wxPropertyStringListEditorDialog *dialog = new wxPropertyStringListEditorDialog(parent,
1777 title, wxPoint(10, 10), wxSize(400, 400), wxDEFAULT_DIALOG_STYLE|wxDIALOG_MODAL);
1778
1779 dialog->m_stringList = stringList;
1780
1781 dialog->m_listBox = new wxListBox(dialog, wxID_PROP_SL_STRINGS,
1782 wxPoint(-1, -1), wxSize(-1, -1), 0, NULL, wxLB_SINGLE);
1783
1784 dialog->m_stringText = new wxPropertyStringListEditorText(dialog,
1785 wxID_PROP_SL_TEXT, "", wxPoint(5, 240),
1786 wxSize(300, -1), wxPROCESS_ENTER);
1787 dialog->m_stringText->Enable(FALSE);
1788
1789 wxButton *addButton = new wxButton(dialog, wxID_PROP_SL_ADD, "Add", wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
1790 wxButton *deleteButton = new wxButton(dialog, wxID_PROP_SL_DELETE, "Delete", wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
1791 wxButton *cancelButton = new wxButton(dialog, wxID_CANCEL, "Cancel", wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
1792 wxButton *okButton = new wxButton(dialog, wxID_OK, "OK", wxPoint(-1, -1), wxSize(largeButtonWidth, largeButtonHeight));
1793
1794 okButton->SetDefault();
1795
1796 wxLayoutConstraints *c = new wxLayoutConstraints;
1797
1798 c->top.SameAs (dialog, wxTop, 2);
1799 c->left.SameAs (dialog, wxLeft, 2);
1800 c->right.SameAs (dialog, wxRight, 2);
1801 c->bottom.SameAs (dialog->m_stringText, wxTop, 2);
1802 dialog->m_listBox->SetConstraints(c);
1803
1804 c = new wxLayoutConstraints;
1805 c->left.SameAs (dialog, wxLeft, 2);
1806 c->right.SameAs (dialog, wxRight, 2);
1807 c->bottom.SameAs (addButton, wxTop, 2);
1808 c->height.AsIs();
1809 dialog->m_stringText->SetConstraints(c);
1810
1811 c = new wxLayoutConstraints;
1812 c->bottom.SameAs (dialog, wxBottom, 2);
1813 c->left.SameAs (dialog, wxLeft, 2);
1814 c->width.AsIs();
1815 c->height.AsIs();
1816 addButton->SetConstraints(c);
1817
1818 c = new wxLayoutConstraints;
1819 c->bottom.SameAs (dialog, wxBottom, 2);
1820 c->left.SameAs (addButton, wxRight, 2);
1821 c->width.AsIs();
1822 c->height.AsIs();
1823 deleteButton->SetConstraints(c);
1824
1825 c = new wxLayoutConstraints;
1826 c->bottom.SameAs (dialog, wxBottom, 2);
1827 c->right.SameAs (dialog, wxRight, 2);
1828 c->width.AsIs();
1829 c->height.AsIs();
1830 cancelButton->SetConstraints(c);
1831
1832 c = new wxLayoutConstraints;
1833 c->bottom.SameAs (dialog, wxBottom, 2);
1834 c->right.SameAs (cancelButton, wxLeft, 2);
1835 c->width.AsIs();
1836 c->height.AsIs();
1837 okButton->SetConstraints(c);
1838
1839 wxNode *node = stringList->First();
1840 while (node)
1841 {
1842 char *str = (char *)node->Data();
1843 // Save node as client data for each listbox item
1844 dialog->m_listBox->Append(str, (char *)node);
1845 node = node->Next();
1846 }
1847
1848 dialog->SetClientSize(310, 305);
1849 dialog->Layout();
1850
1851 dialog->Centre(wxBOTH);
1852 wxEndBusyCursor();
1853 if (dialog->ShowModal() == wxID_CANCEL)
1854 return FALSE;
1855 else
1856 return TRUE;
1857}
1858
1859/*
1860 * String list editor callbacks
1861 *
1862 */
1863
1864void wxPropertyStringListEditorDialog::OnStrings(wxCommandEvent& WXUNUSED(event))
1865{
1866 int sel = m_listBox->GetSelection();
1867 if (sel > -1)
1868 {
1869 m_currentSelection = sel;
1870
1871 ShowCurrentSelection();
1872 }
1873}
1874
1875void wxPropertyStringListEditorDialog::OnDelete(wxCommandEvent& WXUNUSED(event))
1876{
1877 int sel = m_listBox->GetSelection();
1878 if (sel == -1)
1879 return;
1880
1881 wxNode *node = (wxNode *)m_listBox->wxListBox::GetClientData(sel);
1882 if (!node)
1883 return;
1884
1885 m_listBox->Delete(sel);
1886 delete[] (char *)node->Data();
1887 delete node;
1888 m_currentSelection = -1;
1889 m_stringText->SetValue("");
1890}
1891
1892void wxPropertyStringListEditorDialog::OnAdd(wxCommandEvent& WXUNUSED(event))
1893{
1894 SaveCurrentSelection();
1895
1896 char *initialText = "";
1897 wxNode *node = m_stringList->Add(initialText);
1898 m_listBox->Append(initialText, (char *)node);
1899 m_currentSelection = m_stringList->Number() - 1;
1900 m_listBox->SetSelection(m_currentSelection);
1901 ShowCurrentSelection();
1902 m_stringText->SetFocus();
1903}
1904
1905void wxPropertyStringListEditorDialog::OnOK(wxCommandEvent& WXUNUSED(event))
1906{
1907 SaveCurrentSelection();
1908 EndModal(wxID_OK);
3b1e466c
JS
1909 // Close(TRUE);
1910 this->Destroy();
e3a43801
JS
1911}
1912
1913void wxPropertyStringListEditorDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
1914{
1915 sm_dialogCancelled = TRUE;
1916 EndModal(wxID_CANCEL);
3b1e466c
JS
1917// Close(TRUE);
1918 this->Destroy();
e3a43801
JS
1919}
1920
1921void wxPropertyStringListEditorDialog::OnText(wxCommandEvent& event)
1922{
2432b92d 1923 if (event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER)
e3a43801
JS
1924 {
1925 SaveCurrentSelection();
1926 }
1927}
1928
3b1e466c 1929void wxPropertyStringListEditorDialog::OnCloseWindow(wxCloseEvent& event)
e3a43801
JS
1930{
1931 SaveCurrentSelection();
3b1e466c 1932 this->Destroy();
e3a43801
JS
1933}
1934
1935void wxPropertyStringListEditorDialog::SaveCurrentSelection(void)
1936{
1937 if (m_currentSelection == -1)
1938 return;
1939
1940 wxNode *node = (wxNode *)m_listBox->wxListBox::GetClientData(m_currentSelection);
1941 if (!node)
1942 return;
1943
1944 wxString txt(m_stringText->GetValue());
1945 if (node->Data())
1946 delete[] (char *)node->Data();
1947 node->SetData((wxObject *)copystring(txt));
1948
1949 m_listBox->SetString(m_currentSelection, (char *)node->Data());
1950}
1951
1952void wxPropertyStringListEditorDialog::ShowCurrentSelection(void)
1953{
1954 if (m_currentSelection == -1)
1955 {
1956 m_stringText->SetValue("");
1957 return;
1958 }
1959 wxNode *node = (wxNode *)m_listBox->wxListBox::GetClientData(m_currentSelection);
1960 char *txt = (char *)node->Data();
1961 m_stringText->SetValue(txt);
1962 m_stringText->Enable(TRUE);
1963}
1964