1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        samples/propgrid/tests.cpp
3 // Purpose:     wxPropertyGrid tests
4 // Author:      Jaakko Salli
5 // Modified by:
6 // Created:     2007-05-16
7 // Copyright:   (c) Jaakko Salli
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #include "wx/wxprec.h"
12 
13 
14 #ifndef WX_PRECOMP
15     #include "wx/wx.h"
16 #endif
17 
18 #include "wx/propgrid/propgrid.h"
19 #include "wx/propgrid/advprops.h"
20 #include "wx/propgrid/manager.h"
21 
22 #include "propgrid.h"
23 #include "sampleprops.h"
24 
25 
26 // -----------------------------------------------------------------------
27 // wxTestCustomFlagsProperty
28 // -----------------------------------------------------------------------
29 
30 //
31 // Test customizing wxColourProperty via subclassing
32 //
33 // * Includes custom colour entry.
34 // * Includes extra custom entry.
35 //
36 class MyColourProperty : public wxColourProperty
37 {
38 public:
MyColourProperty(const wxString & label=wxPG_LABEL,const wxString & name=wxPG_LABEL,const wxColour & value=* wxWHITE)39     MyColourProperty( const wxString& label = wxPG_LABEL,
40                        const wxString& name = wxPG_LABEL,
41                        const wxColour& value = *wxWHITE )
42         : wxColourProperty(label, name, value)
43     {
44         wxPGChoices colours;
45         colours.Add("White");
46         colours.Add("Black");
47         colours.Add("Red");
48         colours.Add("Green");
49         colours.Add("Blue");
50         colours.Add("Custom");
51         colours.Add("None");
52         m_choices = colours;
53         SetIndex(0);
54         wxVariant variant;
55         variant << value;
56         SetValue(variant);
57     }
58 
~MyColourProperty()59     virtual ~MyColourProperty()
60     {
61     }
62 
GetColour(int index) const63     virtual wxColour GetColour( int index ) const wxOVERRIDE
64     {
65         switch (index)
66         {
67             case 0: return *wxWHITE;
68             case 1: return *wxBLACK;
69             case 2: return *wxRED;
70             case 3: return *wxGREEN;
71             case 4: return *wxBLUE;
72             case 5:
73                 // Return current colour for the custom entry
74                 wxColour col;
75                 if ( GetIndex() == GetCustomColourIndex() )
76                 {
77                     if ( m_value.IsNull() )
78                         return col;
79                     col << m_value;
80                     return col;
81                 }
82                 return *wxWHITE;
83         }
84         return wxColour();
85     }
86 
ColourToString(const wxColour & col,int index,int argFlags=0) const87     virtual wxString ColourToString( const wxColour& col,
88                                      int index,
89                                      int argFlags = 0 ) const wxOVERRIDE
90     {
91         if ( index == (int)(m_choices.GetCount()-1) )
92             return wxEmptyString;
93 
94         return wxColourProperty::ColourToString(col, index, argFlags);
95     }
96 
GetCustomColourIndex() const97     virtual int GetCustomColourIndex() const wxOVERRIDE
98     {
99         return m_choices.GetCount()-2;
100     }
101 };
102 
103 
AddTestProperties(wxPropertyGridPage * pg)104 void FormMain::AddTestProperties( wxPropertyGridPage* pg )
105 {
106     pg->Append( new MyColourProperty("CustomColourProperty", wxPG_LABEL, *wxGREEN) );
107     pg->GetProperty("CustomColourProperty")->SetAutoUnspecified(true);
108     pg->SetPropertyEditor( "CustomColourProperty", wxPGEditor_ComboBox );
109 
110     pg->SetPropertyHelpString("CustomColourProperty",
111         "This is a MyColourProperty from the sample app. "
112         "It is built by subclassing wxColourProperty.");
113 }
114 
115 // -----------------------------------------------------------------------
116 
OnDumpList(wxCommandEvent & WXUNUSED (event))117 void FormMain::OnDumpList( wxCommandEvent& WXUNUSED(event) )
118 {
119     wxVariant values = m_pPropGridManager->GetPropertyValues("list", wxNullProperty, wxPG_INC_ATTRIBUTES);
120     wxString text = "This only tests that wxVariant related routines do not crash.\n";
121 
122     wxDialog* dlg = new wxDialog(this,wxID_ANY,"wxVariant Test",
123         wxDefaultPosition,wxDefaultSize,wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
124 
125     for ( size_t i = 0; i < values.GetCount(); i++ )
126     {
127         wxString t;
128         wxVariant& v = values[i];
129 
130         wxString strValue = v.GetString();
131 
132         if ( v.GetName().EndsWith("@attr") )
133         {
134             text += wxString::Format("Attributes:\n");
135 
136             for ( size_t n = 0; n < v.GetCount(); n++ )
137             {
138                 wxVariant& a = v[n];
139 
140                 t.Printf("  attribute %i: name=\"%s\"  (type=\"%s\"  value=\"%s\")\n",(int)n,
141                     a.GetName(),a.GetType(),a.GetString());
142                 text += t;
143             }
144         }
145         else
146         {
147             t.Printf("%i: name=\"%s\"  type=\"%s\"  value=\"%s\"\n",(int)i,
148                 v.GetName(),v.GetType(),strValue);
149             text += t;
150         }
151     }
152 
153     // multi-line text editor dialog
154     const int spacing = 8;
155     wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
156     wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
157     wxTextCtrl* ed = new wxTextCtrl(dlg, wxID_ANY, text,
158                                     wxDefaultPosition, wxDefaultSize,
159                                     wxTE_MULTILINE|wxTE_READONLY);
160     rowsizer->Add( ed, wxSizerFlags(1).Expand().Border(wxALL, spacing));
161     topsizer->Add( rowsizer, wxSizerFlags(1).Expand());
162     rowsizer = new wxBoxSizer( wxHORIZONTAL );
163     rowsizer->Add( new wxButton(dlg,wxID_OK,"Ok"),
164         wxSizerFlags(0).CentreHorizontal().CentreVertical().Border(wxBOTTOM|wxLEFT|wxRIGHT, spacing));
165     topsizer->Add( rowsizer, wxSizerFlags().Right() );
166 
167     dlg->SetSizer( topsizer );
168     topsizer->SetSizeHints( dlg );
169 
170     dlg->SetSize(400,300);
171     dlg->Centre();
172     dlg->ShowModal();
173 }
174 
175 // -----------------------------------------------------------------------
176 
177 class TestRunner
178 {
179 public:
180 
TestRunner(const wxString & name,wxPropertyGridManager * man,wxTextCtrl * ed,wxVector<wxString> * errorMessages)181     TestRunner( const wxString& name, wxPropertyGridManager* man, wxTextCtrl* ed, wxVector<wxString>* errorMessages )
182     {
183         m_name = name;
184         m_man = man;
185         m_ed = ed;
186         m_errorMessages = errorMessages;
187 #ifdef __WXDEBUG__
188         m_preWarnings = wxPGGlobalVars->m_warnings;
189 #endif
190 
191         if ( name != "none" )
192             Msg(name+"\n");
193     }
194 
~TestRunner()195     ~TestRunner()
196     {
197 #ifdef __WXDEBUG__
198         int warningsOccurred = wxPGGlobalVars->m_warnings - m_preWarnings;
199         if ( warningsOccurred )
200         {
201             wxString s = wxString::Format("%i warnings occurred during test '%s'", warningsOccurred, m_name);
202             m_errorMessages->push_back(s);
203             Msg(s);
204         }
205 #endif
206     }
207 
Msg(const wxString & text)208     void Msg( const wxString& text )
209     {
210         if ( m_ed )
211         {
212             m_ed->AppendText(text);
213             m_ed->AppendText("\n");
214         }
215         wxLogDebug(text);
216     }
217 
218 protected:
219     wxPropertyGridManager* m_man;
220     wxTextCtrl* m_ed;
221     wxVector<wxString>* m_errorMessages;
222     wxString m_name;
223 #ifdef __WXDEBUG__
224     int m_preWarnings;
225 #endif
226 };
227 
228 
229 #define RT_START_TEST(TESTNAME) \
230     TestRunner tr(#TESTNAME, pgman, ed, &errorMessages);
231 
232 #define RT_MSG(S) \
233     tr.Msg(S);
234 
235 #define RT_FAILURE() \
236     { \
237         wxString s1 = wxString::Format("Test failure in tests.cpp, line %i.",__LINE__-1); \
238         errorMessages.push_back(s1); \
239         wxLogDebug(s1); \
240         failures++; \
241     }
242 
243 #define RT_ASSERT(COND) \
244     if (!(COND)) \
245         RT_FAILURE()
246 
247 #define RT_FAILURE_MSG(MSG) \
248     { \
249         wxString s1 = wxString::Format("Test failure in tests.cpp, line %i.",__LINE__-1); \
250         errorMessages.push_back(s1); \
251         wxLogDebug(s1); \
252         wxString s2 = wxString::Format("Message: %s",MSG); \
253         errorMessages.push_back(s2); \
254         wxLogDebug(s2); \
255         failures++; \
256     }
257 
258 #define RT_VALIDATE_VIRTUAL_HEIGHT(PROPS, EXTRATEXT) \
259     { \
260         unsigned int h1_ = PROPS->GetVirtualHeight(); \
261         unsigned int h2_ = PROPS->GetActualVirtualHeight(); \
262         if ( h1_ != h2_ ) \
263         { \
264             wxString s_ = wxString::Format("VirtualHeight = %i, should be %i (%s)", h1_, h2_, EXTRATEXT); \
265             RT_FAILURE_MSG(s_); \
266             _failed_ = true; \
267         } \
268         else \
269         { \
270             _failed_ = false; \
271         } \
272     }
273 
GetRandomBooleanVal()274 inline bool GetRandomBooleanVal()
275 {
276     return (rand() % 2) != 0;
277 }
278 
279 extern "C"
gpiro_cmpfunc(const void * a,const void * b)280 int gpiro_cmpfunc(const void* a, const void* b)
281 {
282     const wxPGProperty* p1 = *static_cast<wxPGProperty* const*>(a);
283     const wxPGProperty* p2 = *static_cast<wxPGProperty* const*>(b);
284     return (int) (((size_t)p1->GetClientData()) - ((size_t)p2->GetClientData()));
285 }
286 
GetPropertiesInRandomOrder(wxPropertyGridInterface * props,int iterationFlags=wxPG_ITERATE_ALL)287 wxVector<wxPGProperty*> GetPropertiesInRandomOrder( wxPropertyGridInterface* props, int iterationFlags = wxPG_ITERATE_ALL )
288 {
289     wxVector<wxPGProperty*> arr;
290 
291     wxPropertyGridIterator it;
292 
293     for ( it = props->GetIterator(iterationFlags);
294           !it.AtEnd();
295           ++it )
296     {
297         wxPGProperty* p = *it;
298         size_t randomNumber = rand();
299         p->SetClientData(reinterpret_cast<void*>(randomNumber));
300         arr.push_back(p);
301     }
302 
303     wxPGProperty** firstEntry = &arr[0];
304     qsort(firstEntry, arr.size(), sizeof(wxPGProperty*), gpiro_cmpfunc);
305 
306     return arr;
307 }
308 
309 // Callback for testing property sorting
MyPropertySortFunction(wxPropertyGrid * WXUNUSED (propGrid),wxPGProperty * p1,wxPGProperty * p2)310 int MyPropertySortFunction(wxPropertyGrid* WXUNUSED(propGrid),
311                            wxPGProperty* p1,
312                            wxPGProperty* p2)
313 {
314     // Reverse alphabetical order
315     return p2->GetLabel().CmpNoCase( p1->GetBaseName() );
316 }
317 
RunTests(bool fullTest,bool interactive)318 bool FormMain::RunTests( bool fullTest, bool interactive )
319 {
320     wxString t;
321 
322     wxPropertyGridManager* pgman = m_pPropGridManager;
323     wxPropertyGrid* pg;
324 
325     size_t i;
326 
327     pgman->ClearSelection();
328 
329     srand((unsigned int)(time(NULL) % UINT_MAX));
330 
331     int failures = 0;
332     bool _failed_ = false;
333     wxVector<wxString> errorMessages;
334     wxDialog* dlg = NULL;
335 
336     dlg = new wxDialog(this,wxID_ANY,"wxPropertyGrid Regression Tests",
337         wxDefaultPosition,wxDefaultSize,wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
338 
339     // multi-line text editor dialog
340     const int spacing = 8;
341     wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
342     wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
343     wxTextCtrl* ed = new wxTextCtrl(dlg, wxID_ANY, wxEmptyString,
344                                     wxDefaultPosition, wxDefaultSize,
345                                     wxTE_MULTILINE|wxTE_READONLY);
346     rowsizer->Add( ed, wxSizerFlags(1).Expand().Border(wxALL, spacing));
347     topsizer->Add( rowsizer, wxSizerFlags(1).Expand());
348     rowsizer = new wxBoxSizer( wxHORIZONTAL );
349     rowsizer->Add( new wxButton(dlg,wxID_OK,"Ok"),
350         wxSizerFlags(0).CentreHorizontal().CentreVertical().Border(wxBOTTOM|wxLEFT|wxRIGHT, spacing));
351     topsizer->Add( rowsizer, wxSizerFlags().Right() );
352 
353     dlg->SetSizer( topsizer );
354     topsizer->SetSizeHints( dlg );
355 
356     dlg->SetSize(400,300);
357     dlg->Move(wxSystemSettings::GetMetric(wxSYS_SCREEN_X)-dlg->GetSize().x,
358               wxSystemSettings::GetMetric(wxSYS_SCREEN_Y)-dlg->GetSize().y);
359     dlg->Show();
360 
361     {
362         //
363         // Basic iterator tests
364         RT_START_TEST(GetIterator)
365 
366         wxPGVIterator it;
367         int count;
368 
369         count = 0;
370         for ( it = pgman->GetVIterator(wxPG_ITERATE_PROPERTIES);
371               !it.AtEnd();
372               it.Next() )
373         {
374             wxPGProperty* p = it.GetProperty();
375             if ( p->IsCategory() )
376                 RT_FAILURE_MSG(wxString::Format("'%s' is a category (non-private child property expected)",p->GetLabel()))
377             else if ( p->GetParent()->HasFlag(wxPG_PROP_AGGREGATE) )
378                 RT_FAILURE_MSG(wxString::Format("'%s' is a private child (non-private child property expected)",p->GetLabel()))
379             count++;
380         }
381 
382         RT_MSG(wxString::Format("GetVIterator(wxPG_ITERATE_PROPERTIES) -> %i entries", count));
383 
384         count = 0;
385         for ( it = pgman->GetVIterator(wxPG_ITERATE_CATEGORIES);
386               !it.AtEnd();
387               it.Next() )
388         {
389             wxPGProperty* p = it.GetProperty();
390             if ( !p->IsCategory() )
391                 RT_FAILURE_MSG(wxString::Format("'%s' is not a category (only category was expected)",p->GetLabel()))
392             count++;
393         }
394 
395         RT_MSG(wxString::Format("GetVIterator(wxPG_ITERATE_CATEGORIES) -> %i entries", count));
396 
397         count = 0;
398         for ( it = pgman->GetVIterator(wxPG_ITERATE_PROPERTIES|wxPG_ITERATE_CATEGORIES);
399               !it.AtEnd();
400               it.Next() )
401         {
402             wxPGProperty* p = it.GetProperty();
403             if ( p->GetParent()->HasFlag(wxPG_PROP_AGGREGATE) )
404                 RT_FAILURE_MSG(wxString::Format("'%s' is a private child (non-private child property or category expected)",p->GetLabel()))
405             count++;
406         }
407 
408         RT_MSG(wxString::Format("GetVIterator(wxPG_ITERATE_PROPERTIES|wxPG_ITERATE_CATEGORIES) -> %i entries", count));
409 
410         count = 0;
411         for ( it = pgman->GetVIterator(wxPG_ITERATE_VISIBLE);
412               !it.AtEnd();
413               it.Next() )
414         {
415             wxPGProperty* p = it.GetProperty();
416             if ( (p->GetParent() != p->GetParentState()->DoGetRoot() && !p->GetParent()->IsExpanded()) )
417                 RT_FAILURE_MSG(wxString::Format("'%s' had collapsed parent (only visible properties expected)",p->GetLabel()))
418             else if ( p->HasFlag(wxPG_PROP_HIDDEN) )
419                 RT_FAILURE_MSG(wxString::Format("'%s' was hidden (only visible properties expected)",p->GetLabel()))
420             count++;
421         }
422 
423         RT_MSG(wxString::Format("GetVIterator(wxPG_ITERATE_VISIBLE) -> %i entries", count));
424     }
425 
426     if ( fullTest )
427     {
428         // Test that setting focus to properties does not crash things
429         RT_START_TEST(SelectProperty)
430 
431         wxPropertyGridIterator it;
432         size_t ind;
433 
434         for ( ind=0; ind<pgman->GetPageCount(); ind++ )
435         {
436             wxPropertyGridPage* page = pgman->GetPage(ind);
437             pgman->SelectPage(page);
438 
439             for ( it = page->GetIterator(wxPG_ITERATE_VISIBLE);
440                   !it.AtEnd();
441                   ++it )
442             {
443                 wxPGProperty* p = *it;
444                 RT_MSG(p->GetLabel());
445                 pgman->GetGrid()->SelectProperty(p, true);
446                 ::wxMilliSleep(150);
447                 Update();
448             }
449         }
450     }
451 
452     {
453         //
454         // Delete everything in reverse order
455         RT_START_TEST(DeleteProperty)
456 
457         wxPGVIterator it;
458         wxVector<wxPGProperty*> array;
459 
460         for ( it = pgman->GetVIterator(wxPG_ITERATE_ALL&~(wxPG_IT_CHILDREN(wxPG_PROP_AGGREGATE)));
461               !it.AtEnd();
462               it.Next() )
463             array.push_back(it.GetProperty());
464 
465         wxVector<wxPGProperty*>::reverse_iterator it2;
466 
467         for ( it2 = array.rbegin(); it2 != array.rend(); ++it2 )
468         {
469             wxPGProperty* p = *it2;
470             RT_MSG(wxString::Format("Deleting '%s' ('%s')",p->GetLabel(),p->GetName()));
471             pgman->DeleteProperty(p);
472         }
473 
474         // Check if grid is empty.
475         it = pgman->GetVIterator(wxPG_ITERATE_ALL&~(wxPG_IT_CHILDREN(wxPG_PROP_AGGREGATE)));
476         if ( !it.AtEnd() )
477         {
478             RT_FAILURE_MSG(wxString("Not all properties are deleted"));
479         }
480 
481         // Recreate grid
482         ReplaceGrid( -1, -1 );
483         pgman = m_pPropGridManager;
484     }
485 
486     {
487         //
488         // Test property default values
489         RT_START_TEST(Default_Values)
490 
491         wxPGVIterator it;
492 
493         for ( it = pgman->GetVIterator(wxPG_ITERATE_PROPERTIES);
494               !it.AtEnd();
495               it.Next() )
496         {
497             wxPGProperty* p = it.GetProperty();
498             pgman->SetPropertyValue(p, p->GetDefaultValue());
499         }
500 
501         // Recreate grid
502         ReplaceGrid( -1, -1 );
503         pgman = m_pPropGridManager;
504     }
505 
506     {
507         //
508         // Test wxAny<->wxVariant conversion
509         RT_START_TEST(WXVARIANT_TO_WXANY_CONVERSION)
510 
511         wxPGProperty* prop;
512         wxAny any;
513 
514 #if wxUSE_DATETIME
515         prop = pgman->GetProperty("DateProperty");
516         wxDateTime testTime = wxDateTime::Now();
517         any = testTime;
518         prop->SetValue(any);
519         if ( prop->GetValue().GetAny().As<wxDateTime>() != testTime )
520             RT_FAILURE();
521 #endif
522 
523         prop = pgman->GetProperty("IntProperty");
524         int testInt = 25537983;
525         any = testInt;
526         prop->SetValue(any);
527         if ( prop->GetValue().GetAny().As<int>() != testInt )
528             RT_FAILURE();
529 #ifdef wxLongLong_t
530         if ( prop->GetValue().GetAny().As<wxLongLong_t>() != testInt )
531             RT_FAILURE();
532 #endif
533 
534         prop = pgman->GetProperty("StringProperty");
535         wxString testString = "asd934jfyn3";
536         any = testString;
537         prop->SetValue(any);
538         if ( prop->GetValue().GetAny().As<wxString>() != testString )
539             RT_FAILURE();
540 
541         // Test with a type generated with IMPLEMENT_VARIANT_OBJECT()
542         prop = pgman->GetProperty("ColourProperty");
543         wxColour testCol = *wxCYAN;
544         any = testCol;
545         prop->SetValue(any);
546         if ( prop->GetValue().GetAny().As<wxColour>() != testCol )
547             RT_FAILURE();
548 
549         // Test with a type with custom wxVariantData defined by
550         // wxPG headers.
551         prop = pgman->GetProperty("Position");
552         wxPoint testPoint(199, 199);
553         any = testPoint;
554         prop->SetValue(any);
555         if ( prop->GetValue().GetAny().As<wxPoint>() != testPoint )
556             RT_FAILURE();
557     }
558 
559     {
560         RT_START_TEST(GetPropertyValues)
561 
562         for ( i=0; i<3; i++ )
563         {
564             wxString text;
565 
566             wxPropertyGridPage* page = pgman->GetPage(i);
567 
568             wxVariant values = page->GetPropertyValues();
569 
570             for (unsigned int j = 0; j < (unsigned int)values.GetCount(); j++ )
571             {
572                 wxVariant& v = values[j];
573 
574                 t.Printf("%i: name=\"%s\"  type=\"%s\"\n",(int)j,
575                     v.GetName(),v.GetType());
576 
577                 text += t;
578             }
579             ed->AppendText(text);
580         }
581     }
582 
583     {
584         RT_START_TEST(SetPropertyValue_and_GetPropertyValue)
585 
586         // In this section, mixed up usage of "propname" and "propname"
587         // in wxPropertyGridInterface functions is intentional.
588         // Purpose is to test wxPGPropArgCls ctors.
589 
590         //pg = (wxPropertyGrid*) NULL;
591 
592         wxArrayString test_arrstr_1;
593         test_arrstr_1.Add("Apple");
594         test_arrstr_1.Add("Orange");
595         test_arrstr_1.Add("Lemon");
596 
597         wxArrayString test_arrstr_2;
598         test_arrstr_2.Add("Potato");
599         test_arrstr_2.Add("Cabbage");
600         test_arrstr_2.Add("Cucumber");
601 
602         wxArrayInt test_arrint_1;
603         test_arrint_1.Add(1);
604         test_arrint_1.Add(2);
605         test_arrint_1.Add(3);
606 
607         wxArrayInt test_arrint_2;
608         test_arrint_2.Add(0);
609         test_arrint_2.Add(1);
610         test_arrint_2.Add(4);
611 
612 #if wxUSE_DATETIME
613         wxDateTime dt1 = wxDateTime::Now();
614         dt1.SetYear(dt1.GetYear()-1);
615 
616         wxDateTime dt2 = wxDateTime::Now();
617         dt2.SetYear(dt2.GetYear()-10);
618 #endif
619 
620         wxColour colWithAlpha(1, 128, 254, 100);
621         wxString colWithAlphaStr(colWithAlpha.GetAsString(wxC2S_CSS_SYNTAX));
622 
623 #define FLAG_TEST_SET1 (wxCAPTION|wxCLOSE_BOX|wxSYSTEM_MENU|wxRESIZE_BORDER)
624 #define FLAG_TEST_SET2 (wxSTAY_ON_TOP|wxCAPTION|wxICONIZE|wxSYSTEM_MENU)
625 
626         pgman->SetPropertyValue("StringProperty","Text1");
627         pgman->SetPropertyValue("IntProperty",1024);
628         pgman->SetPropertyValue("FloatProperty",1024.0000000001);
629         pgman->SetPropertyValue("BoolProperty",false);
630         pgman->SetPropertyValue("EnumProperty",120);
631         pgman->SetPropertyValue("ArrayStringProperty",test_arrstr_1);
632         wxColour emptyCol;
633         pgman->SetPropertyValue("ColourProperty",emptyCol);
634         pgman->SetPropertyValue("ColourProperty", const_cast<wxObject*>(static_cast<const wxObject*>(wxBLACK)));
635         pgman->SetPropertyValue("Size",WXVARIANT(wxSize(150,150)));
636         pgman->SetPropertyValue("Position",WXVARIANT(wxPoint(150,150)));
637         pgman->SetPropertyValue("MultiChoiceProperty",test_arrint_1);
638 #if wxUSE_DATETIME
639         pgman->SetPropertyValue("DateProperty",dt1);
640 #endif
641 
642         pgman->SelectPage(2);
643         pg = pgman->GetGrid();
644 
645         if ( pg->GetPropertyValueAsString("StringProperty") != "Text1" )
646             RT_FAILURE();
647         if ( pg->GetPropertyValueAsInt("IntProperty") != 1024 )
648             RT_FAILURE();
649         if ( pg->GetPropertyValueAsDouble("FloatProperty") != 1024.0000000001 )
650             RT_FAILURE();
651         if ( pg->GetPropertyValueAsBool("BoolProperty") != false )
652             RT_FAILURE();
653         if ( pg->GetPropertyValueAsLong("EnumProperty") != 120 )
654             RT_FAILURE();
655         if ( pg->GetPropertyValueAsArrayString("ArrayStringProperty") != test_arrstr_1 )
656             RT_FAILURE();
657         wxColour col;
658         col << pgman->GetPropertyValue("ColourProperty");
659         if ( col != *wxBLACK )
660             RT_FAILURE();
661         wxVariant varSize(pg->GetPropertyValue("Size"));
662         if ( wxSizeRefFromVariant(varSize) != wxSize(150,150) )
663             RT_FAILURE();
664         wxVariant varPos(pg->GetPropertyValue("Position"));
665         if ( wxPointRefFromVariant(varPos) != wxPoint(150,150) )
666             RT_FAILURE();
667         if ( !(pg->GetPropertyValueAsArrayInt("MultiChoiceProperty") == test_arrint_1) )
668             RT_FAILURE();
669 #if wxUSE_DATETIME
670         if ( !(pg->GetPropertyValueAsDateTime("DateProperty") == dt1) )
671             RT_FAILURE();
672 #endif
673 
674 #if wxUSE_LONGLONG && defined(wxLongLong_t)
675         pgman->SetPropertyValue("IntProperty",wxLL(10000000000));
676         if ( pg->GetPropertyValueAsLongLong("IntProperty") != wxLL(10000000000) )
677             RT_FAILURE();
678 #else
679         pgman->SetPropertyValue("IntProperty",1000000000);
680         if ( pg->GetPropertyValueAsLong("IntProperty") != 1000000000 )
681             RT_FAILURE();
682 #endif
683 
684         pg->SetPropertyValue("StringProperty","Text2");
685         pg->SetPropertyValue("IntProperty",512);
686         pg->SetPropertyValue("FloatProperty",512.0);
687         pg->SetPropertyValue("BoolProperty",true);
688         pg->SetPropertyValue("EnumProperty",80);
689         pg->SetPropertyValue("ArrayStringProperty",test_arrstr_2);
690         pg->SetPropertyValue("ColourProperty", const_cast<wxObject*>(static_cast<const wxObject*>(wxWHITE)));
691         pg->SetPropertyValue("Size",WXVARIANT(wxSize(300,300)));
692         pg->SetPropertyValue("Position",WXVARIANT(wxPoint(300,300)));
693         pg->SetPropertyValue("MultiChoiceProperty",test_arrint_2);
694 #if wxUSE_DATETIME
695         pg->SetPropertyValue("DateProperty",dt2);
696 #endif
697 
698         //pg = (wxPropertyGrid*) NULL;
699 
700         pgman->SelectPage(0);
701 
702         if ( pgman->GetPropertyValueAsString("StringProperty") != "Text2" )
703             RT_FAILURE();
704         if ( pgman->GetPropertyValueAsInt("IntProperty") != 512 )
705             RT_FAILURE();
706         if ( pgman->GetPropertyValueAsDouble("FloatProperty") != 512.0 )
707             RT_FAILURE();
708         if ( pgman->GetPropertyValueAsBool("BoolProperty") != true )
709             RT_FAILURE();
710         if ( pgman->GetPropertyValueAsLong("EnumProperty") != 80 )
711             RT_FAILURE();
712         if ( pgman->GetPropertyValueAsArrayString("ArrayStringProperty") != test_arrstr_2 )
713             RT_FAILURE();
714         col << pgman->GetPropertyValue("ColourProperty");
715         if ( col != *wxWHITE )
716             RT_FAILURE();
717         varSize = pgman->GetPropertyValue("Size");
718         if ( wxSizeRefFromVariant(varSize) != wxSize(300,300) )
719             RT_FAILURE();
720         varPos = pgman->GetPropertyValue("Position");
721         if ( wxPointRefFromVariant(varPos) != wxPoint(300,300) )
722             RT_FAILURE();
723         if ( !(pgman->GetPropertyValueAsArrayInt("MultiChoiceProperty") == test_arrint_2) )
724             RT_FAILURE();
725 #if wxUSE_DATETIME
726         if ( !(pgman->GetPropertyValueAsDateTime("DateProperty") == dt2) )
727             RT_FAILURE();
728 #endif
729 
730 #if wxUSE_LONGLONG && defined(wxLongLong_t)
731         pgman->SetPropertyValue("IntProperty",wxLL(-80000000000));
732         if ( pgman->GetPropertyValueAsLongLong("IntProperty") != wxLL(-80000000000) )
733             RT_FAILURE();
734 #else
735         pgman->SetPropertyValue("IntProperty",-1000000000);
736         if ( pgman->GetPropertyValueAsLong("IntProperty") != -1000000000 )
737             RT_FAILURE();
738 #endif
739 
740         // Make sure children of composite parent get updated as well
741         // Original string value: "Lamborghini Diablo SV; 5707; [300; 3.9; 8.6] 300000; Not Convertible"
742 
743         //
744         // This updates children as well
745         wxString nvs = "Lamborghini Diablo XYZ; 5707; [100; 3.9; 8.6] 3000002; Convertible";
746         pgman->SetPropertyValue("Car", nvs);
747 
748         if ( pgman->GetPropertyValueAsString("Car.Model") != "Lamborghini Diablo XYZ" )
749         {
750             RT_FAILURE_MSG(wxString::Format("Did not match: Car.Model=%s", pgman->GetPropertyValueAsString("Car.Model")));
751         }
752 
753         if ( pgman->GetPropertyValueAsInt("Car.Speeds.Max. Speed (mph)") != 100 )
754         {
755             RT_FAILURE_MSG(wxString::Format("Did not match: Car.Speeds.Max. Speed (mph)=%s", pgman->GetPropertyValueAsString("Car.Speeds.Max. Speed (mph)")));
756         }
757 
758         if ( pgman->GetPropertyValueAsInt("Car.Price ($)") != 3000002 )
759         {
760             RT_FAILURE_MSG(wxString::Format(wxS("Did not match: Car.Price ($)=%s"), pgman->GetPropertyValueAsString(wxS("Car.Price ($)"))));
761         }
762 
763         if ( !pgman->GetPropertyValueAsBool("Car.Convertible") )
764         {
765             RT_FAILURE_MSG(wxString::Format("Did not match: Car.Convertible=%s", pgman->GetPropertyValueAsString("Car.Convertible")));
766         }
767 
768         // SetPropertyValueString for special cases such as wxColour
769         pgman->SetPropertyValueString("ColourProperty", "(123,4,255)");
770         col << pgman->GetPropertyValue("ColourProperty");
771         if ( col != wxColour(123, 4, 255) )
772             RT_FAILURE();
773         pgman->SetPropertyValueString("ColourProperty", "#FE860B");
774         col << pgman->GetPropertyValue("ColourProperty");
775         if ( col != wxColour(254, 134, 11) )
776             RT_FAILURE();
777 
778         pgman->SetPropertyValueString("ColourPropertyWithAlpha",
779                                       "(10, 20, 30, 128)");
780         col << pgman->GetPropertyValue("ColourPropertyWithAlpha");
781         if ( col != wxColour(10, 20, 30, 128) )
782             RT_FAILURE();
783         if ( pgman->GetPropertyValueAsString("ColourPropertyWithAlpha")
784                 != "(10,20,30,128)" )
785             RT_FAILURE();
786     }
787 
788     {
789         RT_START_TEST(SetPropertyValueUnspecified)
790 
791         // Null variant setter tests
792         pgman->SetPropertyValueUnspecified("StringProperty");
793         pgman->SetPropertyValueUnspecified("IntProperty");
794         pgman->SetPropertyValueUnspecified("FloatProperty");
795         pgman->SetPropertyValueUnspecified("BoolProperty");
796         pgman->SetPropertyValueUnspecified("EnumProperty");
797         pgman->SetPropertyValueUnspecified("ArrayStringProperty");
798         pgman->SetPropertyValueUnspecified("ColourProperty");
799         pgman->SetPropertyValueUnspecified("Size");
800         pgman->SetPropertyValueUnspecified("Position");
801         pgman->SetPropertyValueUnspecified("MultiChoiceProperty");
802 #if wxUSE_DATETIME
803         pgman->SetPropertyValueUnspecified("DateProperty");
804 #endif
805     }
806 
807     {
808         //
809         // Test multiple selection
810         RT_START_TEST(MULTIPLE_SELECTION)
811         if ( !(pgman->GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION) )
812             ReplaceGrid( -1, wxPG_EX_MULTIPLE_SELECTION);
813         pgman = m_pPropGridManager;
814 
815         pg = pgman->GetGrid();
816 
817         wxPGProperty* prop1 = pg->GetProperty("Label");
818         wxPGProperty* prop2 = pg->GetProperty("Cell Text Colour");
819         wxPGProperty* prop3 = pg->GetProperty("Height");
820         wxPGProperty* catProp = pg->GetProperty("Appearance");
821 
822         RT_ASSERT( prop1 && prop2 && prop3 );
823 
824         pg->ClearSelection();
825         pg->AddToSelection(prop1);
826         pg->AddToSelection(prop2);
827         pg->AddToSelection(prop3);
828 
829         // Adding category to selection should fail silently
830         pg->AddToSelection(catProp);
831 
832         wxArrayPGProperty selectedProperties = pg->GetSelectedProperties();
833 
834         RT_ASSERT( selectedProperties.size() == 3 )
835         RT_ASSERT( pg->IsPropertySelected(prop1) )
836         RT_ASSERT( pg->IsPropertySelected(prop2) )
837         RT_ASSERT( pg->IsPropertySelected(prop3) )
838         RT_ASSERT( !pg->IsPropertySelected(catProp) )
839 
840         pg->RemoveFromSelection(prop1);
841         wxArrayPGProperty selectedProperties2 = pg->GetSelectedProperties();
842 
843         RT_ASSERT( selectedProperties2.size() == 2 )
844         RT_ASSERT( !pg->IsPropertySelected(prop1) )
845         RT_ASSERT( pg->IsPropertySelected(prop2) )
846         RT_ASSERT( pg->IsPropertySelected(prop3) )
847 
848         pg->ClearSelection();
849 
850         wxArrayPGProperty selectedProperties3 = pg->GetSelectedProperties();
851 
852         RT_ASSERT( selectedProperties3.size() == 0 )
853         RT_ASSERT( !pg->IsPropertySelected(prop1) )
854         RT_ASSERT( !pg->IsPropertySelected(prop2) )
855         RT_ASSERT( !pg->IsPropertySelected(prop3) )
856 
857         pg->SelectProperty(prop2);
858 
859         RT_ASSERT( !pg->IsPropertySelected(prop1) )
860         RT_ASSERT( pg->IsPropertySelected(prop2) )
861         RT_ASSERT( !pg->IsPropertySelected(prop3) )
862     }
863 
864     {
865         //
866         // Test retrieving main parent of the property
867         RT_START_TEST(GetMainParent)
868         pgman = m_pPropGridManager;
869 
870         // Simple properties
871         wxPGProperty* prop = pgman->GetProperty("DateProperty");
872         wxPGProperty* parent = prop->GetMainParent();
873         RT_ASSERT(parent->GetName() == "DateProperty");
874 
875         prop = pgman->GetProperty("Label");
876         parent = prop->GetMainParent();
877         RT_ASSERT(parent->GetName() == "Label");
878 
879         // Properties with children
880         prop = pgman->GetProperty("Font");
881         RT_ASSERT(prop);
882         parent = prop->GetMainParent();
883         RT_ASSERT(parent);
884         RT_ASSERT(parent->GetName() == "Font");
885 
886         prop = pgman->GetProperty("Font.Style");
887         RT_ASSERT(prop);
888         parent = prop->GetMainParent();
889         RT_ASSERT(parent);
890         RT_ASSERT(parent->GetName() == "Font");
891 
892         prop = pgman->GetProperty("Car");
893         RT_ASSERT(prop);
894         parent = prop->GetMainParent();
895         RT_ASSERT(parent);
896         RT_ASSERT(parent->GetName() == "Car");
897 
898         prop = pgman->GetProperty("Car.Model");
899         RT_ASSERT(prop);
900         parent = prop->GetMainParent();
901         RT_ASSERT(parent);
902         RT_ASSERT(parent->GetName() == "Car");
903 
904         prop = pgman->GetProperty("Car.Speeds");
905         RT_ASSERT(prop);
906         parent = prop->GetMainParent();
907         RT_ASSERT(parent);
908         RT_ASSERT(parent->GetName() == "Car");
909 
910         prop = pgman->GetProperty("3D Object.Triangle 3.A");
911         RT_ASSERT(prop);
912         parent = prop->GetMainParent();
913         RT_ASSERT(parent);
914         RT_ASSERT(parent->GetName() == "3D Object");
915 
916         prop = pgman->GetProperty("3D Object.Triangle 3.A.Z");
917         RT_ASSERT(prop);
918         parent = prop->GetMainParent();
919         RT_ASSERT(parent);
920         RT_ASSERT(parent->GetName() == "3D Object");
921     }
922 
923     {
924         //
925         // Test label editing
926         RT_START_TEST(LABEL_EDITING)
927 
928         pg = pgman->GetGrid();
929 
930         // Just mostly test that these won't crash
931         pg->MakeColumnEditable(0, true);
932         pg->MakeColumnEditable(2, true);
933         pg->MakeColumnEditable(0, false);
934         pg->MakeColumnEditable(2, false);
935         pg->SelectProperty("Height");
936         pg->BeginLabelEdit(0);
937         pg->BeginLabelEdit(0);
938         pg->EndLabelEdit(0);
939         pg->EndLabelEdit(0);
940 
941         // Recreate grid
942         ReplaceGrid( -1, -1 );
943         pgman = m_pPropGridManager;
944     }
945 
946     {
947         RT_START_TEST(Attributes)
948 
949         wxPGProperty* prop = pgman->GetProperty("StringProperty");
950         prop->SetAttribute("Dummy Attribute", 15L);
951 
952         if ( prop->GetAttribute("Dummy Attribute").GetLong() != 15L )
953             RT_FAILURE();
954 
955         prop->SetAttribute("Dummy Attribute", wxVariant());
956 
957         if ( !prop->GetAttribute("Dummy Attribute").IsNull() )
958             RT_FAILURE();
959     }
960 
961     {
962         RT_START_TEST(Attributes with PGManager)
963 
964         const long val = 25;
965         pgman->SetPropertyAttribute("IntProperty", "Dummy Attribute", val);
966         if ( pgman->GetPropertyAttribute("IntProperty", "Dummy Attribute").GetLong() != val )
967             RT_FAILURE();
968 
969         pgman->SetPropertyAttribute("IntProperty", "Dummy Attribute", wxVariant());
970         if ( !pgman->GetPropertyAttribute("IntProperty", "Dummy Attribute").IsNull() )
971             RT_FAILURE();
972     }
973 
974     {
975         RT_START_TEST(Getting list of attributes)
976 
977         wxPGProperty* prop = pgman->GetProperty("Height");
978         const wxPGAttributeStorage& attrs1 = prop->GetAttributes();
979         if ( attrs1.GetCount() < 1 )
980             RT_FAILURE();
981 
982         const wxPGAttributeStorage& attrs2 = pgman->GetPropertyAttributes("Height");
983         if ( attrs2.GetCount() != attrs1.GetCount() )
984             RT_FAILURE();
985 
986         // Compare both lists
987         wxVariant val1;
988         wxVariant val2;
989         wxPGAttributeStorage::const_iterator it = attrs1.StartIteration();
990         while ( attrs1.GetNext(it, val1) )
991         {
992             val2 = attrs2.FindValue(val1.GetName());
993             if ( val1 != val2 )
994                 RT_FAILURE();
995         }
996     }
997 
998     {
999         RT_START_TEST(Copying list of attributes)
1000 
1001         wxPGAttributeStorage attrs1(pgman->GetPropertyAttributes("Height"));
1002         if ( attrs1.GetCount() < 1 )
1003             RT_FAILURE();
1004 
1005         wxPGAttributeStorage attrs2;
1006         attrs2 = attrs1;
1007         if ( attrs2.GetCount() != attrs1.GetCount() )
1008             RT_FAILURE();
1009 
1010         // Compare both lists
1011         wxVariant val1;
1012         wxVariant val2;
1013         wxPGAttributeStorage::const_iterator it = attrs1.StartIteration();
1014         while ( attrs1.GetNext(it, val1) )
1015         {
1016             val2 = attrs2.FindValue(val1.GetName());
1017             if ( val1 != val2 )
1018                 RT_FAILURE();
1019         }
1020     }
1021 
1022     {
1023         RT_START_TEST(MaxLength)
1024 
1025         wxPGProperty* prop1 = pgman->GetProperty("StringProperty");
1026         if ( !prop1->SetMaxLength(10) )
1027             RT_FAILURE();
1028         if ( prop1->GetMaxLength() != 10 )
1029             RT_FAILURE();
1030 
1031         if ( !prop1->SetMaxLength(-1) )
1032             RT_FAILURE();
1033         if ( prop1->GetMaxLength() != 0 )
1034             RT_FAILURE();
1035 
1036         wxPGProperty* prop2 = pgman->GetProperty("LongStringProp");
1037         if ( !prop2->SetMaxLength(20) )
1038             RT_FAILURE();
1039         if ( prop2->GetMaxLength() != 20 )
1040             RT_FAILURE();
1041 
1042         wxPGProperty* prop3 = pgman->GetProperty("IntProperty");
1043         if ( !prop3->SetMaxLength(30) )
1044             RT_FAILURE();
1045         if ( prop3->GetMaxLength() != 30 )
1046             RT_FAILURE();
1047 
1048         wxPGProperty* prop4 = pgman->GetProperty("ArrayStringProperty");
1049         if ( !prop4->SetMaxLength(40) )
1050             RT_FAILURE();
1051         if ( prop4->GetMaxLength() != 40 )
1052             RT_FAILURE();
1053 
1054         wxPGProperty* prop5 = pgman->GetProperty("EnumProperty");
1055         if ( prop5->SetMaxLength(50) )
1056             RT_FAILURE();
1057 
1058         wxPGProperty* prop6 = pgman->GetProperty("BoolProperty");
1059         if ( prop6->SetMaxLength(60) )
1060             RT_FAILURE();
1061     }
1062 
1063     {
1064         RT_START_TEST(MaxLength with PG)
1065         pgman->SelectPage(2);
1066         pg = pgman->GetGrid();
1067 
1068         wxPGProperty* prop1 = pgman->GetProperty("StringProperty");
1069         if ( !pg->SetPropertyMaxLength("StringProperty", 110) )
1070             RT_FAILURE();
1071         if ( prop1->GetMaxLength() != 110 )
1072             RT_FAILURE();
1073 
1074         if ( !pg->SetPropertyMaxLength("StringProperty", -1) )
1075             RT_FAILURE();
1076         if ( prop1->GetMaxLength() != 0 )
1077             RT_FAILURE();
1078 
1079         wxPGProperty* prop2 = pgman->GetProperty("LongStringProp");
1080         if ( !pg->SetPropertyMaxLength("LongStringProp", 120) )
1081             RT_FAILURE();
1082         if ( prop2->GetMaxLength() != 120 )
1083             RT_FAILURE();
1084 
1085         wxPGProperty* prop3 = pgman->GetProperty("FloatProperty");
1086         if ( !pg->SetPropertyMaxLength("FloatProperty", 130) )
1087             RT_FAILURE();
1088         if ( prop3->GetMaxLength() != 130 )
1089             RT_FAILURE();
1090 
1091         if ( pg->SetPropertyMaxLength("ColourProperty", 140) )
1092             RT_FAILURE();
1093 
1094         if ( pg->SetPropertyMaxLength("BoolProperty", 150) )
1095             RT_FAILURE();
1096     }
1097 
1098 #if WXWIN_COMPATIBILITY_3_0
1099     {
1100         RT_START_TEST(DoubleToString)
1101 
1102         // Locale-specific decimal separator
1103         wxString sep = wxString::Format("%g", 1.1)[1];
1104 
1105         wxString s;
1106 
1107         if ( wxPropertyGrid::DoubleToString(s, 123.123, 2, true) !=
1108                 wxString::Format("123%s12", sep) )
1109             RT_FAILURE();
1110         if ( wxPropertyGrid::DoubleToString(s, -123.123, 4, false) !=
1111                 wxString::Format("-123%s1230", sep) )
1112             RT_FAILURE();
1113         if ( wxPropertyGrid::DoubleToString(s, -0.02, 1, false) !=
1114                 wxString::Format("0%s0", sep) )
1115             RT_FAILURE();
1116         if ( wxPropertyGrid::DoubleToString(s, -0.000123, 3, true) != "0" )
1117             RT_FAILURE();
1118     }
1119 #endif
1120 
1121     {
1122         wxPropertyGridPage* page1;
1123         wxPropertyGridPage* page2;
1124         wxPropertyGridPage* page3;
1125         wxVariant pg1_values;
1126         wxVariant pg2_values;
1127         wxVariant pg3_values;
1128 
1129         {
1130             RT_START_TEST(GetPropertyValues)
1131 
1132             page1 = pgman->GetPage(0);
1133             pg1_values = page1->GetPropertyValues("Page1",NULL,wxPG_KEEP_STRUCTURE);
1134             page2 = pgman->GetPage(1);
1135             pg2_values = page2->GetPropertyValues("Page2",NULL,wxPG_KEEP_STRUCTURE);
1136             page3 = pgman->GetPage(2);
1137             pg3_values = page3->GetPropertyValues("Page3",NULL,wxPG_KEEP_STRUCTURE);
1138         }
1139 
1140         {
1141             RT_START_TEST(SetPropertyValues)
1142 
1143             page1->SetPropertyValues(pg3_values);
1144             page2->SetPropertyValues(pg1_values);
1145             page3->SetPropertyValues(pg2_values);
1146         }
1147     }
1148 
1149     if ( !pgman->HasFlag(wxPG_HIDE_CATEGORIES) )
1150     {
1151         RT_START_TEST(Collapse_and_GetFirstCategory_and_GetNextCategory)
1152 
1153         for ( i=0; i<3; i++ )
1154         {
1155             wxPropertyGridPage* page = pgman->GetPage(i);
1156 
1157             wxPropertyGridIterator it;
1158 
1159             for ( it = page->GetIterator( wxPG_ITERATE_CATEGORIES );
1160                   !it.AtEnd();
1161                   ++it )
1162             {
1163                 wxPGProperty* p = *it;
1164 
1165                 if ( !page->IsPropertyCategory(p) )
1166                     RT_FAILURE();
1167 
1168                 page->Collapse( p );
1169 
1170                 t.Printf("Collapsing: %s\n",page->GetPropertyLabel(p));
1171                 ed->AppendText(t);
1172             }
1173         }
1174     }
1175 
1176     {
1177         RT_START_TEST(Save_And_RestoreEditableState)
1178 
1179         for ( i=0; i<3; i++ )
1180         {
1181             pgman->SelectPage(i);
1182 
1183             wxString stringState = pgman->SaveEditableState();
1184             bool res = pgman->RestoreEditableState(stringState);
1185             if ( !res )
1186                 RT_FAILURE();
1187         }
1188     }
1189 
1190     //if ( !pgman->HasFlag(wxPG_HIDE_CATEGORIES) )
1191     {
1192         RT_START_TEST(Expand_and_GetFirstCategory_and_GetNextCategory)
1193 
1194         for ( i=0; i<3; i++ )
1195         {
1196             wxPropertyGridPage* page = pgman->GetPage(i);
1197 
1198             wxPropertyGridIterator it;
1199 
1200             for ( it = page->GetIterator( wxPG_ITERATE_CATEGORIES );
1201                   !it.AtEnd();
1202                   ++it )
1203             {
1204                 wxPGProperty* p = *it;
1205 
1206                 if ( !page->IsPropertyCategory(p) )
1207                     RT_FAILURE();
1208 
1209                 page->Expand( p );
1210 
1211                 t.Printf("Expand: %s\n",page->GetPropertyLabel(p));
1212                 ed->AppendText(t);
1213             }
1214         }
1215     }
1216 
1217     {
1218         RT_START_TEST(Choice_Manipulation)
1219 
1220         wxPGProperty* enumProp = pgman->GetProperty("EnumProperty");
1221 
1222         pgman->SelectPage(2);
1223         pgman->SelectProperty(enumProp);
1224         wxASSERT(pgman->GetGrid()->GetSelection() == enumProp);
1225 
1226         const wxPGChoices& choices = enumProp->GetChoices();
1227         int ind = enumProp->InsertChoice("New Choice", choices.GetCount()/2);
1228         enumProp->DeleteChoice(ind);
1229 
1230         // Recreate the original grid
1231         ReplaceGrid( -1, -1 );
1232         pgman = m_pPropGridManager;
1233     }
1234 
1235     //if ( !pgman->HasFlag(wxPG_HIDE_CATEGORIES) )
1236     {
1237         RT_START_TEST(RandomCollapse)
1238 
1239         // Select the most error prone page as visible.
1240         pgman->SelectPage(1);
1241 
1242         for ( i=0; i<3; i++ )
1243         {
1244             wxVector<wxPGProperty*> arr;
1245 
1246             wxPropertyGridPage* page = pgman->GetPage(i);
1247 
1248             wxPropertyGridIterator it;
1249 
1250             for ( it = page->GetIterator( wxPG_ITERATE_CATEGORIES );
1251                   !it.AtEnd();
1252                   ++it )
1253             {
1254                 arr.push_back(*it);
1255             }
1256 
1257             if ( !arr.empty() )
1258             {
1259                 pgman->Collapse( arr[0] );
1260 
1261                 for ( size_t n=arr.size()-1; n>0; n-- )
1262                 {
1263                     pgman->Collapse( arr[n] );
1264                 }
1265             }
1266 
1267         }
1268     }
1269 
1270     {
1271         RT_START_TEST(EnsureVisible)
1272         pgman->EnsureVisible("Cell Colour");
1273     }
1274 
1275     {
1276         RT_START_TEST(RemoveProperty)
1277 
1278         wxPGProperty* p;
1279 
1280         wxPGProperty* origParent =
1281             pgman->GetProperty("Window Styles")->GetParent();
1282 
1283         // For testing purposes, let's set some custom cell colours
1284         p = pgman->GetProperty("Window Styles");
1285         p->SetCell(2, wxPGCell("style"));
1286         p = pgman->RemoveProperty("Window Styles");
1287         pgman->Refresh();
1288         pgman->Update();
1289 
1290         pgman->AppendIn(origParent, p);
1291         wxASSERT( p->GetCell(2).GetText() == "style");
1292         pgman->Refresh();
1293         pgman->Update();
1294     }
1295 
1296     {
1297         RT_START_TEST(SortFunction)
1298 
1299         wxPGProperty* p;
1300 
1301         // Make sure indexes are as supposed
1302 
1303         p = pgman->GetProperty("User Name");
1304         if ( p->GetIndexInParent() != 3 )
1305             RT_FAILURE();
1306 
1307         p = pgman->GetProperty("User Id");
1308         if ( p->GetIndexInParent() != 2 )
1309             RT_FAILURE();
1310 
1311         p = pgman->GetProperty("User Home");
1312         if ( p->GetIndexInParent() != 1 )
1313             RT_FAILURE();
1314 
1315         p = pgman->GetProperty("Operating System");
1316         if ( p->GetIndexInParent() != 0 )
1317             RT_FAILURE();
1318 
1319         pgman->GetGrid()->SetSortFunction(MyPropertySortFunction);
1320 
1321         pgman->GetGrid()->SortChildren("Environment");
1322 
1323         // Make sure indexes have been reversed
1324         p = pgman->GetProperty("User Name");
1325         if ( p->GetIndexInParent() != 0 )
1326             RT_FAILURE();
1327 
1328         p = pgman->GetProperty("User Id");
1329         if ( p->GetIndexInParent() != 1 )
1330             RT_FAILURE();
1331 
1332         p = pgman->GetProperty("User Home");
1333         if ( p->GetIndexInParent() != 2 )
1334             RT_FAILURE();
1335 
1336         p = pgman->GetProperty("Operating System");
1337         if ( p->GetIndexInParent() != 3 )
1338             RT_FAILURE();
1339     }
1340 
1341     {
1342         RT_START_TEST(SetPropertyBackgroundColour)
1343         wxCommandEvent evt;
1344         evt.SetInt(1); // IsChecked() will return true.
1345         evt.SetId(ID_COLOURSCHEME4);
1346         OnCatColours(evt);
1347         OnColourScheme(evt);
1348     }
1349 
1350     {
1351         RT_START_TEST(Clear)
1352 
1353         // Manager clear
1354         pgman->SelectProperty("Label");
1355         pgman->Clear();
1356 
1357         if ( pgman->GetPageCount() )
1358             RT_FAILURE();
1359 
1360         if ( pgman->GetGrid()->GetRoot()->GetChildCount() )
1361             RT_FAILURE();
1362 
1363         // Recreate the original grid
1364         ReplaceGrid( -1, -1 );
1365         pgman = m_pPropGridManager;
1366 
1367         // Grid clear
1368         pgman->SelectProperty("Label");
1369         pgman->GetGrid()->Clear();
1370 
1371         if ( pgman->GetGrid()->GetRoot()->GetChildCount() )
1372             RT_FAILURE();
1373 
1374         // Recreate the original grid
1375         ReplaceGrid( -1, -1 );
1376         pgman = m_pPropGridManager;
1377     }
1378 
1379     {
1380         RT_START_TEST(SetSplitterPosition)
1381 
1382         const int trySplitterPos = 50;
1383 
1384         int style = wxPG_AUTO_SORT;  // wxPG_SPLITTER_AUTO_CENTER;
1385         ReplaceGrid(style, -1);
1386         pgman = m_pPropGridManager;
1387 
1388         pgman->SetSplitterPosition(trySplitterPos);
1389 
1390         if ( pgman->GetGrid()->GetSplitterPosition() != trySplitterPos )
1391             RT_FAILURE_MSG(wxString::Format("Splitter position was %i (should have been %i)",(int)pgman->GetGrid()->GetSplitterPosition(),trySplitterPos));
1392 
1393         wxSize origSz = GetSize();
1394 
1395         wxSize sz = origSz;
1396         sz.IncBy(5, 5);
1397         SetSize(sz);
1398 
1399         if ( pgman->GetGrid()->GetSplitterPosition() != trySplitterPos )
1400             RT_FAILURE_MSG(wxString::Format("Splitter position was %i (should have been %i)",(int)pgman->GetGrid()->GetSplitterPosition(),trySplitterPos));
1401 
1402         SetSize(origSz);
1403 
1404         // Recreate the original grid
1405         ReplaceGrid( -1, -1 );
1406         pgman = m_pPropGridManager;
1407     }
1408 
1409     {
1410         RT_START_TEST(HideProperty)
1411 
1412         wxPropertyGridPage* page = pgman->GetPage(0);
1413 
1414         wxVector<wxPGProperty*> arr1 = GetPropertiesInRandomOrder(page);
1415 
1416         if ( !_failed_ )
1417         {
1418             for ( i=0; i<arr1.size(); i++ )
1419             {
1420                 wxPGProperty* p = arr1[i];
1421                 page->HideProperty(p, true);
1422 
1423                 wxString s = wxString::Format("HideProperty(%i, %s)", (int)i, p->GetLabel());
1424                 RT_VALIDATE_VIRTUAL_HEIGHT(page, s)
1425                 if ( _failed_ )
1426                     break;
1427             }
1428         }
1429 
1430         if ( !_failed_ )
1431         {
1432             wxVector<wxPGProperty*> arr2 = GetPropertiesInRandomOrder(page);
1433 
1434             for ( i=0; i<arr2.size(); i++ )
1435             {
1436                 wxPGProperty* p = arr2[i];
1437                 page->HideProperty(p, false);
1438 
1439                 wxString s = wxString::Format("ShowProperty(%i, %s)", (int)i, p->GetLabel());
1440                 RT_VALIDATE_VIRTUAL_HEIGHT(page, s)
1441                 if ( _failed_ )
1442                     break;
1443             }
1444         }
1445 
1446         //
1447         // Let's do some more, for better consistency
1448         arr1 = GetPropertiesInRandomOrder(page);
1449 
1450         if ( !_failed_ )
1451         {
1452             for ( i=0; i<arr1.size(); i++ )
1453             {
1454                 wxPGProperty* p = arr1[i];
1455                 page->HideProperty(p, true);
1456 
1457                 wxString s = wxString::Format("HideProperty(%i, %s)", (int)i, p->GetLabel());
1458                 RT_VALIDATE_VIRTUAL_HEIGHT(page, s)
1459                 if ( _failed_ )
1460                     break;
1461             }
1462         }
1463 
1464         if ( !_failed_ )
1465         {
1466             wxVector<wxPGProperty*> arr2 = GetPropertiesInRandomOrder(page);
1467 
1468             for ( i=0; i<arr2.size(); i++ )
1469             {
1470                 wxPGProperty* p = arr2[i];
1471                 page->HideProperty(p, false);
1472 
1473                 wxString s = wxString::Format("ShowProperty(%i, %s)", (int)i, p->GetLabel());
1474                 RT_VALIDATE_VIRTUAL_HEIGHT(page, s)
1475                 if ( _failed_ )
1476                     break;
1477             }
1478         }
1479 
1480         //
1481         // Ok, this time only hide half of them
1482         arr1 = GetPropertiesInRandomOrder(page);
1483         arr1.resize(arr1.size()/2);
1484 
1485         if ( !_failed_ )
1486         {
1487             for ( i=0; i<arr1.size(); i++ )
1488             {
1489                 wxPGProperty* p = arr1[i];
1490                 page->HideProperty(p, true);
1491 
1492                 wxString s = wxString::Format("HideProperty(%i, %s)", (int)i, p->GetLabel());
1493                 RT_VALIDATE_VIRTUAL_HEIGHT(page, s)
1494                 if ( _failed_ )
1495                     break;
1496             }
1497         }
1498 
1499         if ( !_failed_ )
1500         {
1501             wxVector<wxPGProperty*> arr2 = GetPropertiesInRandomOrder(page);
1502 
1503             for ( i=0; i<arr2.size(); i++ )
1504             {
1505                 wxPGProperty* p = arr2[i];
1506                 page->HideProperty(p, false);
1507 
1508                 wxString s = wxString::Format("ShowProperty(%i, %s)", (int)i, p->GetLabel());
1509                 RT_VALIDATE_VIRTUAL_HEIGHT(page, s)
1510                 if ( _failed_ )
1511                     break;
1512             }
1513         }
1514 
1515         // Recreate the original grid
1516         ReplaceGrid( -1, -1 );
1517         pgman = m_pPropGridManager;
1518     }
1519 
1520     {
1521         RT_START_TEST(SetFlagsAsString and GetFlagsAsString)
1522 
1523         // Select the most error prone page as visible.
1524         pgman->SelectPage(1);
1525 
1526         for ( i = 0; i < 3; i++ )
1527         {
1528             wxPropertyGridPage* page = pgman->GetPage(i);
1529 
1530             wxPropertyGridIterator it;
1531             for ( it = page->GetIterator(wxPG_ITERATE_VISIBLE);
1532                   !it.AtEnd();
1533                   ++it )
1534             {
1535                 wxPGProperty *p = *it;
1536 
1537                 // Save initial flags
1538                 wxPGProperty::FlagType oldFlags = 0;
1539                 if( p->HasFlag(wxPG_PROP_COLLAPSED) )
1540                 {
1541                     oldFlags |= wxPG_PROP_COLLAPSED;
1542                 }
1543                 if( p->HasFlag(wxPG_PROP_DISABLED) )
1544                 {
1545                     oldFlags |= wxPG_PROP_DISABLED;
1546                 }
1547                 if( p->HasFlag(wxPG_PROP_HIDDEN) )
1548                 {
1549                     oldFlags |= wxPG_PROP_HIDDEN;
1550                 }
1551                 if( p->HasFlag(wxPG_PROP_NOEDITOR) )
1552                 {
1553                     oldFlags |= wxPG_PROP_NOEDITOR;
1554                 }
1555 
1556                 wxString flags;
1557 
1558                 if ( p->IsCategory() )
1559                 {
1560                     if ( GetRandomBooleanVal() )
1561                     {
1562                         if ( !flags.empty() )
1563                         {
1564                             flags.append("|");
1565                         }
1566                         flags.append("COLLAPSED");
1567                     }
1568                 }
1569 
1570                 if (GetRandomBooleanVal() )
1571                 {
1572                     if ( !flags.empty() )
1573                     {
1574                         flags.append("|");
1575                     }
1576                     flags.append("DISABLED");
1577                 }
1578 
1579                 if ( GetRandomBooleanVal() )
1580                 {
1581                     if ( !flags.empty() )
1582                     {
1583                         flags.append("|");
1584                     }
1585                     flags.append("HIDDEN");
1586                 }
1587 
1588                 // Set flags
1589                 p->SetFlagsFromString(flags);
1590 
1591                 // Verify if flags have been properly set
1592                 if ( flags.Find("COLLAPSED") != wxNOT_FOUND &&
1593                      !p->HasFlag(wxPG_PROP_COLLAPSED) )
1594                 {
1595                     RT_FAILURE_MSG(wxString::Format("Error setting flag from string 'COLLAPSED' for property '%s'",
1596                         p->GetName()));
1597                 }
1598                 if ( flags.Find("COLLAPSED") == wxNOT_FOUND &&
1599                      p->HasFlag(wxPG_PROP_COLLAPSED) )
1600                 {
1601                     RT_FAILURE_MSG(wxString::Format("Error resetting flag from string 'COLLAPSED'for property '%s'",
1602                         p->GetName()));
1603                 }
1604                 if ( flags.Find("DISABLED") != wxNOT_FOUND &&
1605                      !p->HasFlag(wxPG_PROP_DISABLED) )
1606                 {
1607                     RT_FAILURE_MSG(wxString::Format("Error setting flag from string 'DISABLED' for property '%s'",
1608                         p->GetName()));
1609                 }
1610                 if ( flags.Find("DISABLED") == wxNOT_FOUND &&
1611                      p->HasFlag(wxPG_PROP_DISABLED) )
1612                 {
1613                     RT_FAILURE_MSG(wxString::Format("Error resetting flag from string 'DISABLED' for property '%s'",
1614                         p->GetName()));
1615                 }
1616                 if ( flags.Find("HIDDEN") != wxNOT_FOUND &&
1617                      !p->HasFlag(wxPG_PROP_HIDDEN) )
1618                 {
1619                     RT_FAILURE_MSG(wxString::Format("Error setting flag from string 'HIDDEN' for property '%s'",
1620                         p->GetName()));
1621                 }
1622                 if ( flags.Find("HIDDEN") == wxNOT_FOUND &&
1623                      p->HasFlag(wxPG_PROP_HIDDEN) )
1624                 {
1625                     RT_FAILURE_MSG(wxString::Format("Error resetting flag from string 'HIDDEN' for property '%s'",
1626                         p->GetName()));
1627                 }
1628 
1629                 // Get individual flags
1630                 bool ok;
1631 
1632                 flags = p->GetFlagsAsString(wxPG_PROP_COLLAPSED);
1633                 if ( p->HasFlag(wxPG_PROP_COLLAPSED) )
1634                 {
1635                     ok = (flags == "COLLAPSED");
1636                 }
1637                 else
1638                 {
1639                     ok = flags.empty();
1640                 }
1641                 if ( !ok )
1642                 {
1643                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_COLLAPSED flag for property '%s'",
1644                         p->GetName()));
1645                 }
1646 
1647                 flags = p->GetFlagsAsString(wxPG_PROP_DISABLED);
1648                 if ( p->HasFlag(wxPG_PROP_DISABLED) )
1649                 {
1650                     ok = (flags == "DISABLED");
1651                 }
1652                 else
1653                 {
1654                     ok = flags.empty();
1655                 }
1656                 if ( !ok )
1657                 {
1658                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_DISABLED flag for property '%s'",
1659                         p->GetName()));
1660                 }
1661 
1662                 flags = p->GetFlagsAsString(wxPG_PROP_HIDDEN);
1663                 if ( p->HasFlag(wxPG_PROP_HIDDEN) )
1664                 {
1665                     ok = (flags == "HIDDEN");
1666                 }
1667                 else
1668                 {
1669                     ok = flags.empty();
1670                 }
1671                 if ( !ok )
1672                 {
1673                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_HIDDEN flag for property '%s'",
1674                         p->GetName()));
1675                 }
1676 
1677                 flags = p->GetFlagsAsString(wxPG_PROP_NOEDITOR);
1678                 if ( p->HasFlag(wxPG_PROP_NOEDITOR) )
1679                 {
1680                     ok = (flags == "NOEDITOR");
1681                 }
1682                 else
1683                 {
1684                     ok = flags.empty();
1685                 }
1686                 if ( !ok )
1687                 {
1688                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_NOEDITOR flag for property '%s'",
1689                         p->GetName()));
1690                 }
1691 
1692                 // Get all flags
1693                 flags = p->GetFlagsAsString(wxPG_STRING_STORED_FLAGS);
1694                 if ( p->HasFlag(wxPG_PROP_COLLAPSED) )
1695                 {
1696                     ok = (flags.Find("COLLAPSED") != wxNOT_FOUND);
1697                 }
1698                 else
1699                 {
1700                     ok = (flags.Find("COLLAPSED") == wxNOT_FOUND);
1701                 }
1702                 if ( !ok )
1703                 {
1704                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_COLLAPSED flag for property '%s'",
1705                         p->GetName()));
1706                 }
1707 
1708                 if ( p->HasFlag(wxPG_PROP_DISABLED) )
1709                 {
1710                     ok = (flags.Find("DISABLED") != wxNOT_FOUND);
1711                 }
1712                 else
1713                 {
1714                     ok = (flags.Find("DISABLED") == wxNOT_FOUND);
1715                 }
1716                 if ( !ok )
1717                 {
1718                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_DISBALED flag for property '%s'",
1719                         p->GetName()));
1720                 }
1721 
1722                 if ( p->HasFlag(wxPG_PROP_HIDDEN) )
1723                 {
1724                     ok = (flags.Find("HIDDEN") != wxNOT_FOUND);
1725                 }
1726                 else
1727                 {
1728                     ok = (flags.Find("HIDDEN") == wxNOT_FOUND);
1729                 }
1730                 if ( !ok )
1731                 {
1732                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_HIDDEN flag for property '%s'",
1733                         p->GetName()));
1734                 }
1735 
1736                 if ( p->HasFlag(wxPG_PROP_NOEDITOR) )
1737                 {
1738                     ok = (flags.Find("NOEDITOR") != wxNOT_FOUND);
1739                 }
1740                 else
1741                 {
1742                     ok = (flags.Find("NOEDITOR") == wxNOT_FOUND);
1743                 }
1744                 if ( !ok )
1745                 {
1746                     RT_FAILURE_MSG(wxString::Format("Invalid string for wxPG_PROP_NOEDITOR flag for property '%s'",
1747                         p->GetName()));
1748                 }
1749 
1750                 // Restore original flags
1751                 p->ChangeFlag(wxPG_PROP_COLLAPSED, (oldFlags & wxPG_PROP_COLLAPSED) != 0);
1752                 p->ChangeFlag(wxPG_PROP_DISABLED, (oldFlags & wxPG_PROP_DISABLED) != 0);
1753                 p->ChangeFlag(wxPG_PROP_HIDDEN, (oldFlags & wxPG_PROP_HIDDEN) != 0);
1754                 p->ChangeFlag(wxPG_PROP_NOEDITOR, (oldFlags & wxPG_PROP_NOEDITOR) != 0);
1755             }
1756         }
1757     }
1758 
1759     if ( fullTest )
1760     {
1761         RT_START_TEST(MultipleColumns)
1762 
1763         // Test with multiple columns
1764         ReplaceGrid( -1, -1 );
1765         pgman = m_pPropGridManager;
1766         for ( i=3; i<12; i+=2 )
1767         {
1768             RT_MSG(wxString::Format("%i columns",(int)i));
1769             pgman->SetColumnCount(i);
1770             Refresh();
1771             Update();
1772             wxMilliSleep(500);
1773         }
1774     }
1775 
1776     if ( fullTest )
1777     {
1778         RT_START_TEST(WindowStyles)
1779 
1780         // Recreate grid with all possible (single) flags
1781         wxASSERT(wxPG_AUTO_SORT == 0x000000010);
1782 
1783         for ( i=4; i<16; i++ )
1784         {
1785             int flag = 1<<i;
1786             RT_MSG(wxString::Format("Style: 0x%X",flag));
1787             ReplaceGrid( flag, -1 );
1788             pgman = m_pPropGridManager;
1789             Update();
1790             wxMilliSleep(500);
1791         }
1792 
1793         wxASSERT(wxPG_EX_INIT_NOCAT == 0x00001000);
1794 
1795         for ( i=12; i<27; i++ )
1796         {
1797             int flag = 1<<i;
1798             RT_MSG(wxString::Format("ExStyle: 0x%X",flag));
1799             ReplaceGrid( -1, flag );
1800             pgman = m_pPropGridManager;
1801             Update();
1802             wxMilliSleep(500);
1803         }
1804 
1805         // Recreate the original grid
1806         ReplaceGrid( -1, -1 );
1807         pgman = m_pPropGridManager;
1808     }
1809 
1810     RT_START_TEST(none)
1811 
1812     bool retVal;
1813 
1814     if ( failures || !errorMessages.empty() )
1815     {
1816         retVal = false;
1817 
1818         wxString s;
1819 #ifdef __WXDEBUG__
1820         if ( failures )
1821 #endif
1822             s = wxString::Format("%i tests failed!!!", failures);
1823 #ifdef __WXDEBUG__
1824         else
1825             s = wxString::Format("All tests were successful, but there were %i warnings!", wxPGGlobalVars->m_warnings);
1826 #endif
1827         RT_MSG(s)
1828         for ( i=0; i<errorMessages.size(); i++ )
1829             RT_MSG(errorMessages[i])
1830         wxMessageBox(s, "Some Tests Failed");
1831     }
1832     else
1833     {
1834         RT_MSG("All tests successful")
1835         retVal = true;
1836 
1837         if ( !interactive )
1838             dlg->Close();
1839     }
1840 
1841     pgman->SelectPage(0);
1842 
1843     // Test may screw up the toolbar, so we need to refresh it.
1844     wxToolBar* toolBar = pgman->GetToolBar();
1845     if ( toolBar )
1846         toolBar->Refresh();
1847 
1848     return retVal;
1849 }
1850 
1851 // -----------------------------------------------------------------------
1852