]> git.saurik.com Git - wxWidgets.git/blame - src/propgrid/property.cpp
'Set to Unspecified' -> 'Set Value to Unspecified'
[wxWidgets.git] / src / propgrid / property.cpp
CommitLineData
1c4293cb
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/propgrid/property.cpp
3// Purpose: wxPGProperty and related support classes
4// Author: Jaakko Salli
5// Modified by:
6// Created: 2008-08-23
ea5af9c5 7// RCS-ID: $Id$
1c4293cb
VZ
8// Copyright: (c) Jaakko Salli
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx/wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
f4bc1aa2
JS
19#if wxUSE_PROPGRID
20
1c4293cb
VZ
21#ifndef WX_PRECOMP
22 #include "wx/defs.h"
23 #include "wx/object.h"
24 #include "wx/hash.h"
25 #include "wx/string.h"
26 #include "wx/log.h"
27 #include "wx/event.h"
28 #include "wx/window.h"
29 #include "wx/panel.h"
30 #include "wx/dc.h"
31 #include "wx/dcmemory.h"
1c4293cb
VZ
32 #include "wx/pen.h"
33 #include "wx/brush.h"
1c4293cb 34 #include "wx/settings.h"
1c4293cb 35 #include "wx/intl.h"
1c4293cb
VZ
36#endif
37
3b211af1 38#include "wx/propgrid/propgrid.h"
1c4293cb
VZ
39
40
41#define PWC_CHILD_SUMMARY_LIMIT 16 // Maximum number of children summarized in a parent property's
42 // value field.
43
44#define PWC_CHILD_SUMMARY_CHAR_LIMIT 64 // Character limit of summary field when not editing
45
1425eca5
JS
46#if wxPG_COMPATIBILITY_1_4
47
48// Used to establish backwards compatiblity
49const char* g_invalidStringContent = "@__TOTALLY_INVALID_STRING__@";
50
51#endif
1c4293cb
VZ
52
53// -----------------------------------------------------------------------
54
55static void wxPGDrawFocusRect( wxDC& dc, const wxRect& rect )
56{
57#if defined(__WXMSW__) && !defined(__WXWINCE__)
58 // FIXME: Use DrawFocusRect code above (currently it draws solid line
59 // for caption focus but works ok for other stuff).
60 // Also, it seems that this code may not work in future wx versions.
61 dc.SetLogicalFunction(wxINVERT);
62
63 wxPen pen(*wxBLACK,1,wxDOT);
64 pen.SetCap(wxCAP_BUTT);
65 dc.SetPen(pen);
66 dc.SetBrush(*wxTRANSPARENT_BRUSH);
67
68 dc.DrawRectangle(rect);
69
70 dc.SetLogicalFunction(wxCOPY);
71#else
72 dc.SetLogicalFunction(wxINVERT);
73
74 dc.SetPen(wxPen(*wxBLACK,1,wxDOT));
75 dc.SetBrush(*wxTRANSPARENT_BRUSH);
76
77 dc.DrawRectangle(rect);
78
79 dc.SetLogicalFunction(wxCOPY);
80#endif
81}
82
83// -----------------------------------------------------------------------
84// wxPGCellRenderer
85// -----------------------------------------------------------------------
86
87wxSize wxPGCellRenderer::GetImageSize( const wxPGProperty* WXUNUSED(property),
88 int WXUNUSED(column),
89 int WXUNUSED(item) ) const
90{
91 return wxSize(0, 0);
92}
93
94void wxPGCellRenderer::DrawText( wxDC& dc, const wxRect& rect,
95 int xOffset, const wxString& text ) const
96{
1c4293cb
VZ
97 dc.DrawText( text,
98 rect.x+xOffset+wxPG_XBEFORETEXT,
99 rect.y+((rect.height-dc.GetCharHeight())/2) );
100}
101
102void wxPGCellRenderer::DrawEditorValue( wxDC& dc, const wxRect& rect,
103 int xOffset, const wxString& text,
104 wxPGProperty* property,
105 const wxPGEditor* editor ) const
106{
1c4293cb
VZ
107 int yOffset = ((rect.height-dc.GetCharHeight())/2);
108
109 if ( editor )
110 {
03647350 111 wxRect rect2(rect);
1c4293cb
VZ
112 rect2.x += xOffset;
113 rect2.y += yOffset;
114 rect2.height -= yOffset;
115 editor->DrawValue( dc, rect2, property, text );
116 }
117 else
118 {
119 dc.DrawText( text,
120 rect.x+xOffset+wxPG_XBEFORETEXT,
121 rect.y+yOffset );
122 }
123}
124
125void wxPGCellRenderer::DrawCaptionSelectionRect( wxDC& dc, int x, int y, int w, int h ) const
126{
127 wxRect focusRect(x,y+((h-dc.GetCharHeight())/2),w,h);
128 wxPGDrawFocusRect(dc,focusRect);
129}
130
131int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& cell, int flags ) const
132{
4aee8334 133 int imageWidth = 0;
1c4293cb 134
d7e2b522
JS
135 // If possible, use cell colours
136 if ( !(flags & DontUseCellBgCol) )
1c4293cb 137 {
d7e2b522
JS
138 dc.SetPen(cell.GetBgCol());
139 dc.SetBrush(cell.GetBgCol());
140 }
1c4293cb 141
d7e2b522
JS
142 if ( !(flags & DontUseCellFgCol) )
143 {
144 dc.SetTextForeground(cell.GetFgCol());
1c4293cb
VZ
145 }
146
a2851207
JS
147 // Draw Background, but only if not rendering in control
148 // (as control already has rendered correct background).
149 if ( !(flags & (Control|ChoicePopup)) )
150 dc.DrawRectangle(rect);
d7e2b522 151
aaf5f986
JS
152 // Use cell font, if provided
153 const wxFont& font = cell.GetFont();
154 if ( font.IsOk() )
155 dc.SetFont(font);
156
1c4293cb
VZ
157 const wxBitmap& bmp = cell.GetBitmap();
158 if ( bmp.Ok() &&
d7e2b522
JS
159 // Do not draw oversized bitmap outside choice popup
160 ((flags & ChoicePopup) || bmp.GetHeight() < rect.height )
1c4293cb
VZ
161 )
162 {
163 dc.DrawBitmap( bmp,
164 rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
165 rect.y + wxPG_CUSTOM_IMAGE_SPACINGY,
166 true );
4aee8334 167 imageWidth = bmp.GetWidth();
1c4293cb
VZ
168 }
169
4aee8334 170 return imageWidth;
1c4293cb
VZ
171}
172
aaf5f986
JS
173void wxPGCellRenderer::PostDrawCell( wxDC& dc,
174 const wxPropertyGrid* propGrid,
175 const wxPGCell& cell,
176 int WXUNUSED(flags) ) const
177{
178 // Revert font
179 const wxFont& font = cell.GetFont();
180 if ( font.IsOk() )
181 dc.SetFont(propGrid->GetFont());
182}
183
1c4293cb
VZ
184// -----------------------------------------------------------------------
185// wxPGDefaultRenderer
186// -----------------------------------------------------------------------
187
188void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect,
189 const wxPropertyGrid* propertyGrid, wxPGProperty* property,
190 int column, int item, int flags ) const
191{
192 bool isUnspecified = property->IsValueUnspecified();
193
194 if ( column == 1 && item == -1 )
195 {
196 int cmnVal = property->GetCommonValue();
197 if ( cmnVal >= 0 )
198 {
199 // Common Value
200 if ( !isUnspecified )
201 DrawText( dc, rect, 0, propertyGrid->GetCommonValueLabel(cmnVal) );
202 return;
203 }
204 }
205
206 const wxPGEditor* editor = NULL;
d7e2b522 207 const wxPGCell* cell = NULL;
1c4293cb
VZ
208
209 wxString text;
4aee8334 210 int imageWidth = 0;
d7e2b522 211 int preDrawFlags = flags;
1c4293cb 212
d7e2b522 213 property->GetDisplayInfo(column, item, flags, &text, &cell);
1c4293cb 214
4aee8334 215 imageWidth = PreDrawCell( dc, rect, *cell, preDrawFlags );
1c4293cb 216
d7e2b522 217 if ( column == 1 )
1c4293cb 218 {
5900bb7c
JS
219 editor = property->GetColumnEditor(column);
220
1c4293cb
VZ
221 if ( !isUnspecified )
222 {
1c4293cb
VZ
223 // Regular property value
224
225 wxSize imageSize = propertyGrid->GetImageSize(property, item);
226
227 wxPGPaintData paintdata;
228 paintdata.m_parent = propertyGrid;
229 paintdata.m_choiceItem = item;
230
231 if ( imageSize.x > 0 )
232 {
233 wxRect imageRect(rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
234 rect.y+wxPG_CUSTOM_IMAGE_SPACINGY,
235 wxPG_CUSTOM_IMAGE_WIDTH,
236 rect.height-(wxPG_CUSTOM_IMAGE_SPACINGY*2));
237
1c4293cb
VZ
238 dc.SetPen( wxPen(propertyGrid->GetCellTextColour(), 1, wxSOLID) );
239
240 paintdata.m_drawnWidth = imageSize.x;
241 paintdata.m_drawnHeight = imageSize.y;
242
b7bc9d80 243 property->OnCustomPaint( dc, imageRect, paintdata );
1c4293cb 244
4aee8334 245 imageWidth = paintdata.m_drawnWidth;
1c4293cb
VZ
246 }
247
1425eca5 248 text = property->GetValueAsString();
1c4293cb
VZ
249
250 // Add units string?
251 if ( propertyGrid->GetColumnCount() <= 2 )
252 {
253 wxString unitsString = property->GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
254 if ( unitsString.length() )
255 text = wxString::Format(wxS("%s %s"), text.c_str(), unitsString.c_str() );
256 }
257 }
258
259 if ( text.length() == 0 )
260 {
261 // Try to show inline help if no text
262 wxVariant vInlineHelp = property->GetAttribute(wxPGGlobalVars->m_strInlineHelp);
263 if ( !vInlineHelp.IsNull() )
264 {
265 text = vInlineHelp.GetString();
266 dc.SetTextForeground(propertyGrid->GetCellDisabledTextColour());
267 }
268 }
269 }
1c4293cb 270
4aee8334
JS
271 int imageOffset = property->GetImageOffset(imageWidth);
272
1c4293cb
VZ
273 DrawEditorValue( dc, rect, imageOffset, text, property, editor );
274
275 // active caption gets nice dotted rectangle
276 if ( property->IsCategory() /*&& column == 0*/ )
277 {
278 if ( flags & Selected )
279 {
50355f75 280 if ( imageOffset > 0 )
4aee8334
JS
281 {
282 imageOffset -= DEFAULT_IMAGE_OFFSET_INCREMENT;
50355f75 283 imageOffset += wxCC_CUSTOM_IMAGE_MARGIN2 + 4;
4aee8334 284 }
1c4293cb
VZ
285
286 DrawCaptionSelectionRect( dc,
287 rect.x+wxPG_XBEFORETEXT-wxPG_CAPRECTXMARGIN+imageOffset,
288 rect.y-wxPG_CAPRECTYMARGIN+1,
289 ((wxPropertyCategory*)property)->GetTextExtent(propertyGrid,
290 propertyGrid->GetCaptionFont())
291 +(wxPG_CAPRECTXMARGIN*2),
292 propertyGrid->GetFontHeight()+(wxPG_CAPRECTYMARGIN*2) );
293 }
294 }
aaf5f986
JS
295
296 PostDrawCell(dc, propertyGrid, *cell, preDrawFlags);
1c4293cb
VZ
297}
298
299wxSize wxPGDefaultRenderer::GetImageSize( const wxPGProperty* property,
300 int column,
301 int item ) const
302{
303 if ( property && column == 1 )
304 {
305 if ( item == -1 )
306 {
307 wxBitmap* bmp = property->GetValueImage();
308
309 if ( bmp && bmp->Ok() )
310 return wxSize(bmp->GetWidth(),bmp->GetHeight());
311 }
312 }
313 return wxSize(0,0);
314}
315
d7e2b522
JS
316// -----------------------------------------------------------------------
317// wxPGCellData
318// -----------------------------------------------------------------------
319
320wxPGCellData::wxPGCellData()
321 : wxObjectRefData()
322{
323 m_hasValidText = false;
324}
325
1c4293cb
VZ
326// -----------------------------------------------------------------------
327// wxPGCell
328// -----------------------------------------------------------------------
329
330wxPGCell::wxPGCell()
d7e2b522 331 : wxObject()
1c4293cb
VZ
332{
333}
334
335wxPGCell::wxPGCell( const wxString& text,
336 const wxBitmap& bitmap,
337 const wxColour& fgCol,
338 const wxColour& bgCol )
d7e2b522
JS
339 : wxObject()
340{
341 wxPGCellData* data = new wxPGCellData();
342 m_refData = data;
343 data->m_text = text;
344 data->m_bitmap = bitmap;
345 data->m_fgCol = fgCol;
346 data->m_bgCol = bgCol;
347 data->m_hasValidText = true;
348}
349
350wxObjectRefData *wxPGCell::CloneRefData( const wxObjectRefData *data ) const
351{
352 wxPGCellData* c = new wxPGCellData();
353 const wxPGCellData* o = (const wxPGCellData*) data;
354 c->m_text = o->m_text;
355 c->m_bitmap = o->m_bitmap;
356 c->m_fgCol = o->m_fgCol;
357 c->m_bgCol = o->m_bgCol;
358 c->m_hasValidText = o->m_hasValidText;
359 return c;
360}
361
362void wxPGCell::SetText( const wxString& text )
363{
364 AllocExclusive();
365
366 GetData()->SetText(text);
367}
368
369void wxPGCell::SetBitmap( const wxBitmap& bitmap )
1c4293cb 370{
d7e2b522
JS
371 AllocExclusive();
372
373 GetData()->SetBitmap(bitmap);
374}
375
376void wxPGCell::SetFgCol( const wxColour& col )
377{
378 AllocExclusive();
379
380 GetData()->SetFgCol(col);
381}
382
aaf5f986
JS
383void wxPGCell::SetFont( const wxFont& font )
384{
385 AllocExclusive();
386
387 GetData()->SetFont(font);
388}
389
d7e2b522
JS
390void wxPGCell::SetBgCol( const wxColour& col )
391{
392 AllocExclusive();
393
394 GetData()->SetBgCol(col);
395}
396
397void wxPGCell::MergeFrom( const wxPGCell& srcCell )
398{
399 AllocExclusive();
400
401 wxPGCellData* data = GetData();
402
403 if ( srcCell.HasText() )
404 data->SetText(srcCell.GetText());
405
406 if ( srcCell.GetFgCol().IsOk() )
407 data->SetFgCol(srcCell.GetFgCol());
408
409 if ( srcCell.GetBgCol().IsOk() )
410 data->SetBgCol(srcCell.GetBgCol());
411
412 if ( srcCell.GetBitmap().IsOk() )
413 data->SetBitmap(srcCell.GetBitmap());
1c4293cb
VZ
414}
415
416// -----------------------------------------------------------------------
417// wxPGProperty
418// -----------------------------------------------------------------------
419
420IMPLEMENT_ABSTRACT_CLASS(wxPGProperty, wxObject)
421
422wxString* wxPGProperty::sm_wxPG_LABEL = NULL;
423
424void wxPGProperty::Init()
425{
426 m_commonValue = -1;
427 m_arrIndex = 0xFFFF;
428 m_parent = NULL;
429
d3b9f782 430 m_parentState = NULL;
1c4293cb
VZ
431
432 m_clientData = NULL;
433 m_clientObject = NULL;
434
d3b9f782 435 m_customEditor = NULL;
1c4293cb 436#if wxUSE_VALIDATORS
d3b9f782 437 m_validator = NULL;
1c4293cb 438#endif
d3b9f782 439 m_valueBitmap = NULL;
1c4293cb
VZ
440
441 m_maxLen = 0; // infinite maximum length
442
443 m_flags = wxPG_PROP_PROPERTY;
444
445 m_depth = 1;
1c4293cb
VZ
446
447 SetExpanded(true);
448}
449
450
451void wxPGProperty::Init( const wxString& label, const wxString& name )
452{
453 // We really need to check if &label and &name are NULL pointers
454 // (this can if we are called before property grid has been initalized)
455
456 if ( (&label) != NULL && label != wxPG_LABEL )
457 m_label = label;
458
459 if ( (&name) != NULL && name != wxPG_LABEL )
460 DoSetName( name );
461 else
462 DoSetName( m_label );
463
464 Init();
465}
466
2fd4a524
JS
467void wxPGProperty::InitAfterAdded( wxPropertyGridPageState* pageState,
468 wxPropertyGrid* propgrid )
469{
470 //
471 // Called after property has been added to grid or page
472 // (so propgrid can be NULL, too).
473
474 wxPGProperty* parent = m_parent;
475 bool parentIsRoot = parent->IsKindOf(CLASSINFO(wxPGRootProperty));
476
477 m_parentState = pageState;
478
1425eca5
JS
479#if wxPG_COMPATIBILITY_1_4
480 // Make sure deprecated virtual functions are not implemented
481 wxString s = GetValueAsString( 0xFFFF );
482 wxASSERT_MSG( s == g_invalidStringContent,
483 "Implement ValueToString() instead of GetValueAsString()" );
484#endif
485
d7e2b522 486 if ( !parentIsRoot && !parent->IsCategory() )
2fd4a524 487 {
d7e2b522 488 m_cells = parent->m_cells;
2fd4a524
JS
489 }
490
491 // If in hideable adding mode, or if assigned parent is hideable, then
492 // make this one hideable.
493 if (
494 ( !parentIsRoot && parent->HasFlag(wxPG_PROP_HIDDEN) ) ||
495 ( propgrid && (propgrid->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES)) )
496 )
497 SetFlag( wxPG_PROP_HIDDEN );
498
499 // Set custom image flag.
500 int custImgHeight = OnMeasureImage().y;
501 if ( custImgHeight < 0 )
502 {
503 SetFlag(wxPG_PROP_CUSTOMIMAGE);
504 }
505
506 if ( propgrid && (propgrid->HasFlag(wxPG_LIMITED_EDITING)) )
507 SetFlag(wxPG_PROP_NOEDITOR);
508
509 // Make sure parent has some parental flags
510 if ( !parent->HasFlag(wxPG_PROP_PARENTAL_FLAGS) )
511 parent->SetParentalType(wxPG_PROP_MISC_PARENT);
512
513 if ( !IsCategory() )
514 {
515 // This is not a category.
516
517 // Depth.
518 //
519 unsigned char depth = 1;
520 if ( !parentIsRoot )
521 {
522 depth = parent->m_depth;
523 if ( !parent->IsCategory() )
524 depth++;
525 }
526 m_depth = depth;
527 unsigned char greyDepth = depth;
528
529 if ( !parentIsRoot )
530 {
531 wxPropertyCategory* pc;
532
533 if ( parent->IsCategory() )
534 pc = (wxPropertyCategory* ) parent;
535 else
536 // This conditional compile is necessary to
537 // bypass some compiler bug.
538 pc = pageState->GetPropertyCategory(parent);
539
540 if ( pc )
541 greyDepth = pc->GetDepth();
542 else
543 greyDepth = parent->m_depthBgCol;
544 }
545
546 m_depthBgCol = greyDepth;
547 }
548 else
549 {
550 // This is a category.
551
552 // depth
553 unsigned char depth = 1;
554 if ( !parentIsRoot )
555 {
556 depth = parent->m_depth + 1;
557 }
558 m_depth = depth;
559 m_depthBgCol = depth;
560 }
561
562 //
563 // Has initial children
564 if ( GetChildCount() )
565 {
2fd4a524 566 // Check parental flags
48a32cf6
JS
567 wxASSERT_MSG( ((m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
568 wxPG_PROP_AGGREGATE) ||
569 ((m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
570 wxPG_PROP_MISC_PARENT),
571 "wxPGProperty parental flags set incorrectly at "
572 "this time" );
2fd4a524
JS
573
574 if ( HasFlag(wxPG_PROP_AGGREGATE) )
575 {
576 // Properties with private children are not expanded by default.
577 SetExpanded(false);
578 }
579 else if ( propgrid && propgrid->HasFlag(wxPG_HIDE_MARGIN) )
580 {
581 // ...unless it cannot be expanded by user and therefore must
582 // remain visible at all times
583 SetExpanded(true);
584 }
585
586 //
587 // Prepare children recursively
588 for ( unsigned int i=0; i<GetChildCount(); i++ )
589 {
590 wxPGProperty* child = Item(i);
591 child->InitAfterAdded(pageState, pageState->GetGrid());
592 }
593
594 if ( propgrid && (propgrid->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES) )
595 SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED, true);
596 }
597}
598
1c4293cb
VZ
599wxPGProperty::wxPGProperty()
600 : wxObject()
601{
602 Init();
603}
604
605
606wxPGProperty::wxPGProperty( const wxString& label, const wxString& name )
607 : wxObject()
608{
609 Init( label, name );
610}
611
612
613wxPGProperty::~wxPGProperty()
614{
615 delete m_clientObject;
616
617 Empty(); // this deletes items
618
619 delete m_valueBitmap;
620#if wxUSE_VALIDATORS
621 delete m_validator;
622#endif
623
1c4293cb
VZ
624 // This makes it easier for us to detect dangling pointers
625 m_parent = NULL;
626}
627
628
629bool wxPGProperty::IsSomeParent( wxPGProperty* candidate ) const
630{
631 wxPGProperty* parent = m_parent;
632 do
633 {
634 if ( parent == candidate )
635 return true;
636 parent = parent->m_parent;
637 } while ( parent );
638 return false;
639}
640
5fdb6350
JS
641void wxPGProperty::SetName( const wxString& newName )
642{
643 wxPropertyGrid* pg = GetGrid();
644
645 if ( pg )
646 pg->SetPropertyName(this, newName);
647 else
648 DoSetName(newName);
649}
1c4293cb
VZ
650
651wxString wxPGProperty::GetName() const
652{
653 wxPGProperty* parent = GetParent();
654
655 if ( !m_name.length() || !parent || parent->IsCategory() || parent->IsRoot() )
656 return m_name;
657
658 return m_parent->GetName() + wxS(".") + m_name;
659}
660
661wxPropertyGrid* wxPGProperty::GetGrid() const
662{
663 if ( !m_parentState )
664 return NULL;
665 return m_parentState->GetGrid();
666}
667
f7a094e1
JS
668int wxPGProperty::Index( const wxPGProperty* p ) const
669{
670 for ( unsigned int i = 0; i<m_children.size(); i++ )
671 {
672 if ( p == m_children[i] )
673 return i;
674 }
675 return wxNOT_FOUND;
676}
1c4293cb 677
1c4293cb
VZ
678bool wxPGProperty::ValidateValue( wxVariant& WXUNUSED(value), wxPGValidationInfo& WXUNUSED(validationInfo) ) const
679{
680 return true;
681}
682
683void wxPGProperty::OnSetValue()
684{
685}
686
687void wxPGProperty::RefreshChildren ()
688{
689}
690
d8812c6e
JS
691void wxPGProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) )
692{
693}
694
d7e2b522
JS
695void wxPGProperty::GetDisplayInfo( unsigned int column,
696 int choiceIndex,
697 int flags,
698 wxString* pString,
699 const wxPGCell** pCell )
700{
701 const wxPGCell* cell = NULL;
702
703 if ( !(flags & wxPGCellRenderer::ChoicePopup) )
704 {
705 // Not painting listi of choice popups, so get text from property
706 cell = &GetCell(column);
707 if ( cell->HasText() )
708 {
709 *pString = cell->GetText();
710 }
711 else
712 {
713 if ( column == 0 )
714 *pString = GetLabel();
715 else if ( column == 1 )
716 *pString = GetDisplayedString();
717 else if ( column == 2 )
718 *pString = GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
719 }
720 }
721 else
722 {
723 wxASSERT( column == 1 );
724
725 if ( choiceIndex != wxNOT_FOUND )
726 {
727 const wxPGChoiceEntry& entry = m_choices[choiceIndex];
728 if ( entry.GetBitmap().IsOk() ||
729 entry.GetFgCol().IsOk() ||
730 entry.GetBgCol().IsOk() )
731 cell = &entry;
732 *pString = m_choices.GetLabel(choiceIndex);
733 }
734 }
735
736 if ( !cell )
737 cell = &GetCell(column);
738
739 wxASSERT_MSG( cell->GetData(),
740 wxString::Format("Invalid cell for property %s",
741 GetName().c_str()) );
742
743 *pCell = cell;
744}
745
746/*
747wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
1c4293cb 748{
03647350 749
d7e2b522 750 if ( col != 1 || choiceIndex == wxNOT_FOUND )
1c4293cb 751 {
d7e2b522
JS
752 const wxPGCell& cell = GetCell(col);
753 if ( cell->HasText() )
754 {
755 return cell->GetText();
756 }
757 else
758 {
759 if ( col == 0 )
760 return GetLabel();
761 else if ( col == 1 )
762 return GetDisplayedString();
763 else if ( col == 2 )
764 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
765 }
1c4293cb
VZ
766 }
767 else
768 {
d7e2b522
JS
769 // Use choice
770 return m_choices.GetLabel(choiceIndex);
1c4293cb
VZ
771 }
772
773 return wxEmptyString;
774}
d7e2b522 775*/
1c4293cb 776
c82a80e8
JS
777void wxPGProperty::DoGenerateComposedValue( wxString& text,
778 int argFlags,
779 const wxVariantList* valueOverrides,
780 wxPGHashMapS2S* childResults ) const
1c4293cb
VZ
781{
782 int i;
f7a094e1 783 int iMax = m_children.size();
1c4293cb
VZ
784
785 text.clear();
786 if ( iMax == 0 )
787 return;
788
789 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
790 !(argFlags & wxPG_FULL_VALUE) )
791 iMax = PWC_CHILD_SUMMARY_LIMIT;
792
793 int iMaxMinusOne = iMax-1;
794
795 if ( !IsTextEditable() )
796 argFlags |= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT;
797
f7a094e1 798 wxPGProperty* curChild = m_children[0];
1c4293cb 799
1425eca5
JS
800 bool overridesLeft = false;
801 wxVariant overrideValue;
802 wxVariantList::const_iterator node;
803
804 if ( valueOverrides )
805 {
806 node = valueOverrides->begin();
807 if ( node != valueOverrides->end() )
808 {
809 overrideValue = *node;
810 overridesLeft = true;
811 }
812 }
813
1c4293cb
VZ
814 for ( i = 0; i < iMax; i++ )
815 {
1425eca5
JS
816 wxVariant childValue;
817
818 wxString childLabel = curChild->GetLabel();
819
820 // Check for value override
821 if ( overridesLeft && overrideValue.GetName() == childLabel )
822 {
823 if ( !overrideValue.IsNull() )
824 childValue = overrideValue;
825 else
826 childValue = curChild->GetValue();
b7bc9d80 827 ++node;
1425eca5
JS
828 if ( node != valueOverrides->end() )
829 overrideValue = *node;
830 else
831 overridesLeft = false;
832 }
833 else
834 {
835 childValue = curChild->GetValue();
836 }
837
1c4293cb 838 wxString s;
1425eca5
JS
839 if ( !childValue.IsNull() )
840 {
841 if ( overridesLeft &&
842 curChild->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
843 childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
844 {
845 wxVariantList& childList = childValue.GetList();
c82a80e8
JS
846 DoGenerateComposedValue(s, argFlags|wxPG_COMPOSITE_FRAGMENT,
847 &childList, childResults);
1425eca5
JS
848 }
849 else
850 {
851 s = curChild->ValueToString(childValue,
852 argFlags|wxPG_COMPOSITE_FRAGMENT);
853 }
854 }
03647350 855
1425eca5
JS
856 if ( childResults && curChild->GetChildCount() )
857 (*childResults)[curChild->GetName()] = s;
1c4293cb
VZ
858
859 bool skip = false;
860 if ( (argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT) && !s.length() )
861 skip = true;
862
863 if ( !curChild->GetChildCount() || skip )
864 text += s;
865 else
866 text += wxS("[") + s + wxS("]");
867
868 if ( i < iMaxMinusOne )
869 {
870 if ( text.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT &&
871 !(argFlags & wxPG_EDITABLE_VALUE) &&
872 !(argFlags & wxPG_FULL_VALUE) )
873 break;
874
875 if ( !skip )
876 {
877 if ( !curChild->GetChildCount() )
878 text += wxS("; ");
879 else
880 text += wxS(" ");
881 }
882
f7a094e1 883 curChild = m_children[i+1];
1c4293cb
VZ
884 }
885 }
886
f7a094e1 887 if ( (unsigned int)i < m_children.size() )
7036fd20
JS
888 {
889 if ( !text.EndsWith(wxS("; ")) )
890 text += wxS("; ...");
891 else
892 text += wxS("...");
893 }
1c4293cb
VZ
894}
895
1425eca5
JS
896wxString wxPGProperty::ValueToString( wxVariant& WXUNUSED(value),
897 int argFlags ) const
1c4293cb
VZ
898{
899 wxCHECK_MSG( GetChildCount() > 0,
900 wxString(),
1425eca5
JS
901 "If user property does not have any children, it must "
902 "override GetValueAsString" );
903
904 // FIXME: Currently code below only works if value is actually m_value
905 wxASSERT_MSG( argFlags & wxPG_VALUE_IS_CURRENT,
906 "Sorry, currently default wxPGProperty::ValueToString() "
907 "implementation only works if value is m_value." );
1c4293cb
VZ
908
909 wxString text;
c82a80e8 910 DoGenerateComposedValue(text, argFlags);
1c4293cb
VZ
911 return text;
912}
913
1425eca5 914wxString wxPGProperty::GetValueAsString( int argFlags ) const
1c4293cb 915{
1425eca5
JS
916#if wxPG_COMPATIBILITY_1_4
917 // This is backwards compatibility test
918 // That is, to make sure this function is not overridden
919 // (instead, ValueToString() should be).
920 if ( argFlags == 0xFFFF )
921 {
922 // Do not override! (for backwards compliancy)
923 return g_invalidStringContent;
924 }
925#endif
926
1c4293cb
VZ
927 if ( IsValueUnspecified() )
928 return wxEmptyString;
929
930 if ( m_commonValue == -1 )
1425eca5
JS
931 {
932 wxVariant value(GetValue());
933 return ValueToString(value, argFlags|wxPG_VALUE_IS_CURRENT);
934 }
1c4293cb
VZ
935
936 //
937 // Return common value's string representation
938 wxPropertyGrid* pg = GetGrid();
939 const wxPGCommonValue* cv = pg->GetCommonValue(m_commonValue);
940
941 if ( argFlags & wxPG_FULL_VALUE )
942 {
943 return cv->GetLabel();
944 }
945 else if ( argFlags & wxPG_EDITABLE_VALUE )
946 {
947 return cv->GetEditableText();
948 }
949 else
950 {
951 return cv->GetLabel();
952 }
953}
954
1425eca5
JS
955wxString wxPGProperty::GetValueString( int argFlags ) const
956{
957 return GetValueAsString(argFlags);
958}
959
1c4293cb
VZ
960bool wxPGProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const
961{
962 variant = (long)number;
963 return true;
964}
965
966// Convert semicolon delimited tokens into child values.
967bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
968{
969 if ( !GetChildCount() )
970 return false;
971
972 unsigned int curChild = 0;
973
f7a094e1 974 unsigned int iMax = m_children.size();
1c4293cb
VZ
975
976 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
977 !(argFlags & wxPG_FULL_VALUE) )
978 iMax = PWC_CHILD_SUMMARY_LIMIT;
979
980 bool changed = false;
981
982 wxString token;
983 size_t pos = 0;
984
985 // Its best only to add non-empty group items
986 bool addOnlyIfNotEmpty = false;
987 const wxChar delimeter = wxS(';');
988
989 size_t tokenStart = 0xFFFFFF;
990
991 wxVariantList temp_list;
992 wxVariant list(temp_list);
993
f275b5db 994 int propagatedFlags = argFlags & (wxPG_REPORT_ERROR|wxPG_PROGRAMMATIC_VALUE);
1c4293cb 995
4b6a582b
VZ
996 wxLogTrace("propgrid",
997 wxT(">> %s.StringToValue('%s')"), GetLabel(), text);
1c4293cb
VZ
998
999 wxString::const_iterator it = text.begin();
1000 wxUniChar a;
1001
1002 if ( it != text.end() )
1003 a = *it;
1004 else
1005 a = 0;
1006
1007 for ( ;; )
1008 {
a64a1bf7
JS
1009 // How many units we iterate string forward at the end of loop?
1010 // We need to keep track of this or risk going to negative
1011 // with it-- operation.
1012 unsigned int strPosIncrement = 1;
1013
1c4293cb
VZ
1014 if ( tokenStart != 0xFFFFFF )
1015 {
1016 // Token is running
1017 if ( a == delimeter || a == 0 )
1018 {
1019 token = text.substr(tokenStart,pos-tokenStart);
1020 token.Trim(true);
1021 size_t len = token.length();
1022
1023 if ( !addOnlyIfNotEmpty || len > 0 )
1024 {
1025 const wxPGProperty* child = Item(curChild);
f275b5db 1026 wxVariant variant(child->GetValue());
ae82388e 1027 wxString childName = child->GetBaseName();
f275b5db 1028
4b6a582b
VZ
1029 wxLogTrace("propgrid",
1030 wxT("token = '%s', child = %s"),
1031 token, childName);
1c4293cb 1032
f275b5db
JS
1033 // Add only if editable or setting programmatically
1034 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
1035 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1c4293cb 1036 {
f275b5db 1037 if ( len > 0 )
1c4293cb 1038 {
ae82388e
JS
1039 if ( child->StringToValue(variant, token,
1040 propagatedFlags|wxPG_COMPOSITE_FRAGMENT) )
1c4293cb 1041 {
ae82388e
JS
1042 // We really need to set the variant's name
1043 // *after* child->StringToValue() has been
1044 // called, since variant's value may be set by
1045 // assigning another variant into it, which
1046 // then usually causes name to be copied (ie.
1047 // usually cleared) as well. wxBoolProperty
1048 // being case in point with its use of
1049 // wxPGVariant_Bool macro as an optimization.
1050 variant.SetName(childName);
f275b5db 1051 list.Append(variant);
1c4293cb 1052
f275b5db
JS
1053 changed = true;
1054 }
1055 }
1056 else
1057 {
1058 // Empty, becomes unspecified
1059 variant.MakeNull();
ae82388e 1060 variant.SetName(childName);
f275b5db 1061 list.Append(variant);
1c4293cb
VZ
1062 changed = true;
1063 }
1064 }
1c4293cb
VZ
1065
1066 curChild++;
1067 if ( curChild >= iMax )
1068 break;
1069 }
1070
1071 tokenStart = 0xFFFFFF;
1072 }
1073 }
1074 else
1075 {
1076 // Token is not running
1077 if ( a != wxS(' ') )
1078 {
1079
1080 addOnlyIfNotEmpty = false;
1081
1082 // Is this a group of tokens?
1083 if ( a == wxS('[') )
1084 {
1085 int depth = 1;
1086
b7bc9d80 1087 if ( it != text.end() ) ++it;
1c4293cb
VZ
1088 pos++;
1089 size_t startPos = pos;
1090
1091 // Group item - find end
1092 while ( it != text.end() && depth > 0 )
1093 {
1094 a = *it;
b7bc9d80 1095 ++it;
1c4293cb
VZ
1096 pos++;
1097
1098 if ( a == wxS(']') )
1099 depth--;
1100 else if ( a == wxS('[') )
1101 depth++;
1102 }
1103
1104 token = text.substr(startPos,pos-startPos-1);
1105
1106 if ( !token.length() )
1107 break;
1108
1109 const wxPGProperty* child = Item(curChild);
1110
2bbd3749
JS
1111 wxVariant oldChildValue = child->GetValue();
1112 wxVariant variant(oldChildValue);
f275b5db
JS
1113
1114 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
1115 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1c4293cb 1116 {
a64a1bf7
JS
1117 wxString childName = child->GetBaseName();
1118
1119 bool stvRes = child->StringToValue( variant, token,
1120 propagatedFlags );
f275b5db
JS
1121 if ( stvRes || (variant != oldChildValue) )
1122 {
a64a1bf7
JS
1123 variant.SetName(childName);
1124 list.Append(variant);
1125
1126 changed = true;
f275b5db
JS
1127 }
1128 else
1129 {
a64a1bf7 1130 // No changes...
f275b5db 1131 }
1c4293cb
VZ
1132 }
1133
1134 curChild++;
1135 if ( curChild >= iMax )
1136 break;
1137
1138 addOnlyIfNotEmpty = true;
1139
1140 tokenStart = 0xFFFFFF;
1141 }
1142 else
1143 {
1144 tokenStart = pos;
1145
1146 if ( a == delimeter )
a64a1bf7 1147 strPosIncrement -= 1;
1c4293cb
VZ
1148 }
1149 }
1150 }
1151
1152 if ( a == 0 )
1153 break;
1154
a64a1bf7
JS
1155 it += strPosIncrement;
1156
1c4293cb
VZ
1157 if ( it != text.end() )
1158 {
1159 a = *it;
1160 }
1161 else
1162 {
1163 a = 0;
1164 }
a64a1bf7
JS
1165
1166 pos += strPosIncrement;
1c4293cb
VZ
1167 }
1168
1169 if ( changed )
1170 variant = list;
1171
1172 return changed;
1173}
1174
1175bool wxPGProperty::SetValueFromString( const wxString& text, int argFlags )
1176{
1177 wxVariant variant(m_value);
1178 bool res = StringToValue(variant, text, argFlags);
1179 if ( res )
1180 SetValue(variant);
1181 return res;
1182}
1183
1184bool wxPGProperty::SetValueFromInt( long number, int argFlags )
1185{
1186 wxVariant variant(m_value);
1187 bool res = IntToValue(variant, number, argFlags);
1188 if ( res )
1189 SetValue(variant);
1190 return res;
1191}
1192
1193wxSize wxPGProperty::OnMeasureImage( int WXUNUSED(item) ) const
1194{
1195 if ( m_valueBitmap )
1196 return wxSize(m_valueBitmap->GetWidth(),-1);
1197
1198 return wxSize(0,0);
1199}
1200
4aee8334
JS
1201int wxPGProperty::GetImageOffset( int imageWidth ) const
1202{
1203 int imageOffset = 0;
1204
1205 if ( imageWidth )
1206 {
1207 // Do not increment offset too much for wide images
1208 if ( imageWidth <= (wxPG_CUSTOM_IMAGE_WIDTH+5) )
1209 imageOffset = imageWidth + DEFAULT_IMAGE_OFFSET_INCREMENT;
1210 else
1211 imageOffset = imageWidth + 1;
1212 }
1213
1214 return imageOffset;
1215}
1216
1c4293cb
VZ
1217wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const
1218{
1219 return wxPGGlobalVars->m_defaultRenderer;
1220}
1221
1222void wxPGProperty::OnCustomPaint( wxDC& dc,
1223 const wxRect& rect,
1224 wxPGPaintData& )
1225{
1226 wxBitmap* bmp = m_valueBitmap;
1227
1228 wxCHECK_RET( bmp && bmp->Ok(), wxT("invalid bitmap") );
1229
1230 wxCHECK_RET( rect.x >= 0, wxT("unexpected measure call") );
1231
1232 dc.DrawBitmap(*bmp,rect.x,rect.y);
1233}
1234
1235const wxPGEditor* wxPGProperty::DoGetEditorClass() const
1236{
c26873c8 1237 return wxPGEditor_TextCtrl;
1c4293cb
VZ
1238}
1239
1240// Default extra property event handling - that is, none at all.
1241bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& )
1242{
1243 return false;
1244}
1245
1246
1247void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags )
1248{
104837f2
JS
1249 // If auto unspecified values are not wanted (via window or property style),
1250 // then get default value instead of wxNullVariant.
1251 if ( value.IsNull() && (flags & wxPG_SETVAL_BY_USER) &&
1252 !UsesAutoUnspecified() )
1253 {
1254 value = GetDefaultValue();
1255 }
1256
1c4293cb
VZ
1257 if ( !value.IsNull() )
1258 {
8f18b252
JS
1259 wxVariant tempListVariant;
1260
1c4293cb
VZ
1261 SetCommonValue(-1);
1262 // List variants are reserved a special purpose
1263 // as intermediate containers for child values
1264 // of properties with children.
0372d42e 1265 if ( value.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb 1266 {
8f18b252
JS
1267 //
1268 // However, situation is different for composed string properties
1269 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
1270 {
1271 tempListVariant = value;
1272 pList = &tempListVariant;
1273 }
1274
1c4293cb
VZ
1275 wxVariant newValue;
1276 AdaptListToValue(value, &newValue);
1277 value = newValue;
1278 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1279 }
1280
1281 if ( HasFlag( wxPG_PROP_AGGREGATE) )
1282 flags |= wxPG_SETVAL_AGGREGATED;
1283
1284 if ( pList && !pList->IsNull() )
1285 {
0372d42e 1286 wxASSERT( pList->GetType() == wxPG_VARIANT_TYPE_LIST );
1c4293cb
VZ
1287 wxASSERT( GetChildCount() );
1288 wxASSERT( !IsCategory() );
1289
1290 wxVariantList& list = pList->GetList();
1291 wxVariantList::iterator node;
1292 unsigned int i = 0;
1293
1294 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1295
1296 // Children in list can be in any order, but we will give hint to
d665918b 1297 // GetPropertyByNameWH(). This optimizes for full list parsing.
b7bc9d80 1298 for ( node = list.begin(); node != list.end(); ++node )
1c4293cb
VZ
1299 {
1300 wxVariant& childValue = *((wxVariant*)*node);
d665918b 1301 wxPGProperty* child = GetPropertyByNameWH(childValue.GetName(), i);
1c4293cb
VZ
1302 if ( child )
1303 {
d665918b 1304 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
0372d42e 1305 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
1306 {
1307 if ( child->HasFlag(wxPG_PROP_AGGREGATE) && !(flags & wxPG_SETVAL_AGGREGATED) )
1308 {
1309 wxVariant listRefCopy = childValue;
1310 child->SetValue(childValue, &listRefCopy, flags|wxPG_SETVAL_FROM_PARENT);
1311 }
1312 else
1313 {
1314 wxVariant oldVal = child->GetValue();
1315 child->SetValue(oldVal, &childValue, flags|wxPG_SETVAL_FROM_PARENT);
1316 }
1317 }
0372d42e 1318 else if ( child->GetValue() != childValue )
1c4293cb
VZ
1319 {
1320 // For aggregate properties, we will trust RefreshChildren()
1321 // to update child values.
1322 if ( !HasFlag(wxPG_PROP_AGGREGATE) )
1323 child->SetValue(childValue, NULL, flags|wxPG_SETVAL_FROM_PARENT);
8f18b252
JS
1324 if ( flags & wxPG_SETVAL_BY_USER )
1325 child->SetFlag(wxPG_PROP_MODIFIED);
1c4293cb
VZ
1326 }
1327 }
1328 i++;
1329 }
1330 }
1331
1332 if ( !value.IsNull() )
1333 {
0372d42e 1334 m_value = value;
1c4293cb 1335 OnSetValue();
1c4293cb
VZ
1336 }
1337
8f18b252 1338 if ( flags & wxPG_SETVAL_BY_USER )
1c4293cb
VZ
1339 SetFlag(wxPG_PROP_MODIFIED);
1340
1341 if ( HasFlag(wxPG_PROP_AGGREGATE) )
1342 RefreshChildren();
1343 }
1344 else
1345 {
1346 if ( m_commonValue != -1 )
1347 {
1348 wxPropertyGrid* pg = GetGrid();
1349 if ( !pg || m_commonValue != pg->GetUnspecifiedCommonValue() )
1350 SetCommonValue(-1);
1351 }
1352
1353 m_value = value;
1354
1355 // Set children to unspecified, but only if aggregate or
1356 // value is <composed>
1357 if ( AreChildrenComponents() )
1358 {
1359 unsigned int i;
1360 for ( i=0; i<GetChildCount(); i++ )
1361 Item(i)->SetValue(value, NULL, flags|wxPG_SETVAL_FROM_PARENT);
1362 }
1363 }
1364
daeb4e4d
JS
1365 if ( !(flags & wxPG_SETVAL_FROM_PARENT) )
1366 UpdateParentValues();
1367
1c4293cb
VZ
1368 //
1369 // Update editor control
1370 //
1371
1372 // We need to check for these, otherwise GetGrid() may fail.
1373 if ( flags & wxPG_SETVAL_REFRESH_EDITOR )
e777bd14 1374 {
1c4293cb 1375 RefreshEditor();
e777bd14
JS
1376 wxPropertyGrid* pg = GetGridIfDisplayed();
1377 if ( pg )
1378 pg->DrawItemAndValueRelated(this);
1379 }
1c4293cb
VZ
1380}
1381
1382
1383void wxPGProperty::SetValueInEvent( wxVariant value ) const
1384{
1385 GetGrid()->ValueChangeInEvent(value);
1386}
1387
1388void wxPGProperty::SetFlagRecursively( FlagType flag, bool set )
1389{
d58526d5 1390 ChangeFlag(flag, set);
1c4293cb
VZ
1391
1392 unsigned int i;
1393 for ( i = 0; i < GetChildCount(); i++ )
1394 Item(i)->SetFlagRecursively(flag, set);
1395}
1396
1397void wxPGProperty::RefreshEditor()
1398{
f521bae6
JS
1399 if ( !m_parent )
1400 return;
1c4293cb 1401
f521bae6
JS
1402 wxPropertyGrid* pg = GetGrid();
1403 if ( pg && pg->GetSelectedProperty() == this )
a6353fe8 1404 pg->RefreshEditor();
f521bae6 1405}
1c4293cb
VZ
1406
1407wxVariant wxPGProperty::GetDefaultValue() const
1408{
0ce8e27f 1409 wxVariant defVal = GetAttribute(wxPG_ATTR_DEFAULT_VALUE);
1c4293cb
VZ
1410 if ( !defVal.IsNull() )
1411 return defVal;
1412
1413 wxVariant value = GetValue();
1414
1415 if ( !value.IsNull() )
1416 {
0372d42e
JS
1417 wxString valueType(value.GetType());
1418
1419 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1c4293cb 1420 return wxPGVariant_Zero;
0372d42e 1421 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1c4293cb 1422 return wxPGVariant_EmptyString;
0372d42e 1423 if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1c4293cb 1424 return wxPGVariant_False;
0372d42e 1425 if ( valueType == wxPG_VARIANT_TYPE_DOUBLE )
1c4293cb 1426 return wxVariant(0.0);
0372d42e 1427 if ( valueType == wxPG_VARIANT_TYPE_ARRSTRING )
1c4293cb 1428 return wxVariant(wxArrayString());
0372d42e
JS
1429 if ( valueType == wxS("wxLongLong") )
1430 return WXVARIANT(wxLongLong(0));
1431 if ( valueType == wxS("wxULongLong") )
1432 return WXVARIANT(wxULongLong(0));
1433 if ( valueType == wxS("wxColour") )
1434 return WXVARIANT(*wxBLACK);
1c4293cb 1435#if wxUSE_DATETIME
0372d42e 1436 if ( valueType == wxPG_VARIANT_TYPE_DATETIME )
1c4293cb
VZ
1437 return wxVariant(wxDateTime::Now());
1438#endif
0372d42e
JS
1439 if ( valueType == wxS("wxFont") )
1440 return WXVARIANT(*wxNORMAL_FONT);
1441 if ( valueType == wxS("wxPoint") )
1442 return WXVARIANT(wxPoint(0, 0));
1443 if ( valueType == wxS("wxSize") )
1444 return WXVARIANT(wxSize(0, 0));
1c4293cb
VZ
1445 }
1446
1447 return wxVariant();
1448}
1449
d7e2b522
JS
1450void wxPGProperty::EnsureCells( unsigned int column )
1451{
1452 if ( column >= m_cells.size() )
1453 {
1454 // Fill empty slots with default cells
1455 wxPropertyGrid* pg = GetGrid();
1456 wxPGCell defaultCell;
1457
521f1d83
JS
1458 // Work around possible VC6 bug by using intermediate variables
1459 const wxPGCell& propDefCell = pg->GetPropertyDefaultCell();
1460 const wxPGCell& catDefCell = pg->GetCategoryDefaultCell();
1461
d7e2b522 1462 if ( !HasFlag(wxPG_PROP_CATEGORY) )
521f1d83 1463 defaultCell = propDefCell;
d7e2b522 1464 else
521f1d83 1465 defaultCell = catDefCell;
d7e2b522
JS
1466
1467 // TODO: Replace with resize() call
1468 unsigned int cellCountMax = column+1;
1469
1470 for ( unsigned int i=m_cells.size(); i<cellCountMax; i++ )
1471 m_cells.push_back(defaultCell);
1472 }
1473}
1474
1475void wxPGProperty::SetCell( int column,
1476 const wxPGCell& cell )
1477{
1478 EnsureCells(column);
1479
1480 m_cells[column] = cell;
1481}
1482
1483void wxPGProperty::AdaptiveSetCell( unsigned int firstCol,
1484 unsigned int lastCol,
1485 const wxPGCell& cell,
1486 const wxPGCell& srcData,
1487 wxPGCellData* unmodCellData,
1488 FlagType ignoreWithFlags,
1489 bool recursively )
1490{
1491 //
1492 // Sets cell in memory optimizing fashion. That is, if
1493 // current cell data matches unmodCellData, we will
1494 // simply get reference to data from cell. Otherwise,
1495 // cell information from srcData is merged into current.
1496 //
1497
1498 if ( !(m_flags & ignoreWithFlags) && !IsRoot() )
1499 {
1500 EnsureCells(lastCol);
1501
1502 for ( unsigned int col=firstCol; col<=lastCol; col++ )
1503 {
1504 if ( m_cells[col].GetData() == unmodCellData )
1505 {
1506 // Data matches... use cell directly
1507 m_cells[col] = cell;
1508 }
1509 else
1510 {
1511 // Data did not match... merge valid information
1512 m_cells[col].MergeFrom(srcData);
1513 }
1514 }
1515 }
1516
1517 if ( recursively )
1518 {
1519 for ( unsigned int i=0; i<GetChildCount(); i++ )
1520 Item(i)->AdaptiveSetCell( firstCol,
1521 lastCol,
1522 cell,
1523 srcData,
1524 unmodCellData,
1525 ignoreWithFlags,
1526 recursively );
1527 }
1528}
1529
1530const wxPGCell& wxPGProperty::GetCell( unsigned int column ) const
1c4293cb 1531{
d7e2b522
JS
1532 if ( m_cells.size() > column )
1533 return m_cells[column];
1534
1535 wxPropertyGrid* pg = GetGrid();
1536
1537 if ( IsCategory() )
1538 return pg->GetCategoryDefaultCell();
1539
1540 return pg->GetPropertyDefaultCell();
1541}
1542
58935d4a 1543wxPGCell& wxPGProperty::GetOrCreateCell( unsigned int column )
d7e2b522
JS
1544{
1545 EnsureCells(column);
1546 return m_cells[column];
1547}
1548
1549void wxPGProperty::SetBackgroundColour( const wxColour& colour,
e607eac2 1550 int flags )
d7e2b522
JS
1551{
1552 wxPGProperty* firstProp = this;
e607eac2 1553 bool recursively = flags & wxPG_RECURSE ? true : false;
d7e2b522
JS
1554
1555 //
1556 // If category is tried to set recursively, skip it and only
1557 // affect the children.
1558 if ( recursively )
1559 {
1560 while ( firstProp->IsCategory() )
1561 {
1562 if ( !firstProp->GetChildCount() )
1563 return;
1564 firstProp = firstProp->Item(0);
1565 }
1566 }
1567
1568 wxPGCell& firstCell = firstProp->GetCell(0);
1569 wxPGCellData* firstCellData = firstCell.GetData();
1570
1571 wxPGCell newCell(firstCell);
1572 newCell.SetBgCol(colour);
1573 wxPGCell srcCell;
1574 srcCell.SetBgCol(colour);
1575
1576 AdaptiveSetCell( 0,
1577 GetParentState()->GetColumnCount()-1,
1578 newCell,
1579 srcCell,
1580 firstCellData,
1581 recursively ? wxPG_PROP_CATEGORY : 0,
1582 recursively );
1583}
1584
1585void wxPGProperty::SetTextColour( const wxColour& colour,
e607eac2 1586 int flags )
d7e2b522
JS
1587{
1588 wxPGProperty* firstProp = this;
e607eac2 1589 bool recursively = flags & wxPG_RECURSE ? true : false;
d7e2b522
JS
1590
1591 //
1592 // If category is tried to set recursively, skip it and only
1593 // affect the children.
1594 if ( recursively )
1595 {
1596 while ( firstProp->IsCategory() )
1597 {
1598 if ( !firstProp->GetChildCount() )
1599 return;
1600 firstProp = firstProp->Item(0);
1601 }
1602 }
1c4293cb 1603
d7e2b522
JS
1604 wxPGCell& firstCell = firstProp->GetCell(0);
1605 wxPGCellData* firstCellData = firstCell.GetData();
1606
1607 wxPGCell newCell(firstCell);
1608 newCell.SetFgCol(colour);
1609 wxPGCell srcCell;
1610 srcCell.SetFgCol(colour);
1611
1612 AdaptiveSetCell( 0,
1613 GetParentState()->GetColumnCount()-1,
1614 newCell,
1615 srcCell,
1616 firstCellData,
1617 recursively ? wxPG_PROP_CATEGORY : 0,
1618 recursively );
1c4293cb
VZ
1619}
1620
1c4293cb
VZ
1621wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const
1622{
1623 return NULL;
1624}
1625
1626bool wxPGProperty::DoSetAttribute( const wxString& WXUNUSED(name), wxVariant& WXUNUSED(value) )
1627{
1628 return false;
1629}
1630
1631void wxPGProperty::SetAttribute( const wxString& name, wxVariant value )
1632{
1633 if ( DoSetAttribute( name, value ) )
1634 {
1635 // Support working without grid, when possible
1636 if ( wxPGGlobalVars->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES ) )
1637 return;
1638 }
1639
1640 m_attributes.Set( name, value );
1641}
1642
1643void wxPGProperty::SetAttributes( const wxPGAttributeStorage& attributes )
1644{
1645 wxPGAttributeStorage::const_iterator it = attributes.StartIteration();
1646 wxVariant variant;
1647
1648 while ( attributes.GetNext(it, variant) )
1649 SetAttribute( variant.GetName(), variant );
1650}
1651
1652wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
1653{
1654 return wxVariant();
1655}
1656
1657
1658wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
1659{
1660 return m_attributes.FindValue(name);
1661}
1662
1663wxString wxPGProperty::GetAttribute( const wxString& name, const wxString& defVal ) const
1664{
1665 wxVariant variant = m_attributes.FindValue(name);
1666
1667 if ( !variant.IsNull() )
1668 return variant.GetString();
1669
1670 return defVal;
1671}
1672
1673long wxPGProperty::GetAttributeAsLong( const wxString& name, long defVal ) const
1674{
1675 wxVariant variant = m_attributes.FindValue(name);
1676
4e00b908
JS
1677 if ( variant.IsNull() )
1678 return defVal;
1679
1680 return variant.GetLong();
1c4293cb
VZ
1681}
1682
1683double wxPGProperty::GetAttributeAsDouble( const wxString& name, double defVal ) const
1684{
1c4293cb
VZ
1685 wxVariant variant = m_attributes.FindValue(name);
1686
4e00b908
JS
1687 if ( variant.IsNull() )
1688 return defVal;
1c4293cb 1689
4e00b908 1690 return variant.GetDouble();
1c4293cb
VZ
1691}
1692
1693wxVariant wxPGProperty::GetAttributesAsList() const
1694{
1695 wxVariantList tempList;
1696 wxVariant v( tempList, wxString::Format(wxS("@%s@attr"),m_name.c_str()) );
1697
1698 wxPGAttributeStorage::const_iterator it = m_attributes.StartIteration();
1699 wxVariant variant;
1700
1701 while ( m_attributes.GetNext(it, variant) )
1702 v.Append(variant);
1703
1704 return v;
1705}
1706
1707// Slots of utility flags are NULL
1708const unsigned int gs_propFlagToStringSize = 14;
1709
a243da29 1710static const wxChar* const gs_propFlagToString[gs_propFlagToStringSize] = {
1c4293cb
VZ
1711 NULL,
1712 wxT("DISABLED"),
1713 wxT("HIDDEN"),
1714 NULL,
1715 wxT("NOEDITOR"),
1716 wxT("COLLAPSED"),
1717 NULL,
1718 NULL,
1719 NULL,
1720 NULL,
1721 NULL,
1722 NULL,
1723 NULL,
1724 NULL
1725};
1726
1727wxString wxPGProperty::GetFlagsAsString( FlagType flagsMask ) const
1728{
1729 wxString s;
1730 int relevantFlags = m_flags & flagsMask & wxPG_STRING_STORED_FLAGS;
1731 FlagType a = 1;
1732
1733 unsigned int i = 0;
1734 for ( i=0; i<gs_propFlagToStringSize; i++ )
1735 {
1736 if ( relevantFlags & a )
1737 {
1738 const wxChar* fs = gs_propFlagToString[i];
1739 wxASSERT(fs);
1740 if ( s.length() )
1741 s << wxS("|");
1742 s << fs;
1743 }
1744 a = a << 1;
1745 }
1746
1747 return s;
1748}
1749
1750void wxPGProperty::SetFlagsFromString( const wxString& str )
1751{
1752 FlagType flags = 0;
1753
1754 WX_PG_TOKENIZER1_BEGIN(str, wxS('|'))
1755 unsigned int i;
1756 for ( i=0; i<gs_propFlagToStringSize; i++ )
1757 {
1758 const wxChar* fs = gs_propFlagToString[i];
1759 if ( fs && str == fs )
1760 {
1761 flags |= (1<<i);
1762 break;
1763 }
1764 }
1765 WX_PG_TOKENIZER1_END()
1766
1767 m_flags = (m_flags & ~wxPG_STRING_STORED_FLAGS) | flags;
1768}
1769
1770wxValidator* wxPGProperty::DoGetValidator() const
1771{
d3b9f782 1772 return NULL;
1c4293cb
VZ
1773}
1774
939d9364 1775int wxPGProperty::InsertChoice( const wxString& label, int index, int value )
1c4293cb 1776{
939d9364
JS
1777 wxPropertyGrid* pg = GetGrid();
1778 int sel = GetChoiceSelection();
1779
1780 int newSel = sel;
1781
1782 if ( index == wxNOT_FOUND )
1783 index = m_choices.GetCount();
1784
1785 if ( index <= sel )
1786 newSel++;
1787
1788 m_choices.Insert(label, index, value);
1789
1790 if ( sel != newSel )
1791 SetChoiceSelection(newSel);
1792
1793 if ( this == pg->GetSelection() )
1794 GetEditorClass()->InsertItem(pg->GetEditorControl(),label,index);
1795
1796 return index;
1c4293cb
VZ
1797}
1798
939d9364
JS
1799
1800void wxPGProperty::DeleteChoice( int index )
1c4293cb 1801{
939d9364
JS
1802 wxPropertyGrid* pg = GetGrid();
1803
1804 int sel = GetChoiceSelection();
1805 int newSel = sel;
1806
1807 // Adjust current value
1808 if ( sel == index )
1809 {
1810 SetValueToUnspecified();
1811 newSel = 0;
1812 }
1813 else if ( index < sel )
1814 {
1815 newSel--;
1816 }
1817
1818 m_choices.RemoveAt(index);
1819
1820 if ( sel != newSel )
1821 SetChoiceSelection(newSel);
1822
1823 if ( this == pg->GetSelection() )
1824 GetEditorClass()->DeleteItem(pg->GetEditorControl(), index);
1c4293cb
VZ
1825}
1826
939d9364 1827int wxPGProperty::GetChoiceSelection() const
1c4293cb 1828{
939d9364
JS
1829 wxVariant value = GetValue();
1830 wxString valueType = value.GetType();
1831 int index = wxNOT_FOUND;
1832
1833 if ( IsValueUnspecified() || !m_choices.GetCount() )
1834 return wxNOT_FOUND;
1835
1836 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1837 {
1838 index = value.GetLong();
1839 }
1840 else if ( valueType == wxPG_VARIANT_TYPE_STRING )
1841 {
1842 index = m_choices.Index(value.GetString());
1843 }
1844 else if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1845 {
1846 index = value.GetBool()? 1 : 0;
1847 }
1848
1849 return index;
1c4293cb
VZ
1850}
1851
939d9364 1852void wxPGProperty::SetChoiceSelection( int newValue )
1c4293cb 1853{
939d9364
JS
1854 // Changes value of a property with choices, but only
1855 // works if the value type is long or string.
1856 wxString valueType = GetValue().GetType();
1857
1858 wxCHECK_RET( m_choices.IsOk(), wxT("invalid choiceinfo") );
1c4293cb 1859
939d9364
JS
1860 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1861 {
1862 SetValue( m_choices.GetLabel(newValue) );
1863 }
1864 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1865 {
1866 SetValue( (long) newValue );
1867 }
1c4293cb
VZ
1868}
1869
1870bool wxPGProperty::SetChoices( wxPGChoices& choices )
1871{
939d9364 1872 m_choices.Assign(choices);
1c4293cb 1873
1c4293cb 1874 {
939d9364
JS
1875 // This may be needed to trigger some initialization
1876 // (but don't do it if property is somewhat uninitialized)
1877 wxVariant defVal = GetDefaultValue();
1878 if ( defVal.IsNull() )
1879 return false;
1c4293cb 1880
939d9364 1881 SetValue(defVal);
1c4293cb 1882 }
939d9364
JS
1883
1884 return true;
1c4293cb
VZ
1885}
1886
1887
1888const wxPGEditor* wxPGProperty::GetEditorClass() const
1889{
1890 const wxPGEditor* editor;
1891
1892 if ( !m_customEditor )
1893 {
1894 editor = DoGetEditorClass();
1895 }
1896 else
1897 editor = m_customEditor;
1898
1899 //
1900 // Maybe override editor if common value specified
1901 if ( GetDisplayedCommonValueCount() )
1902 {
1903 // TextCtrlAndButton -> ComboBoxAndButton
1904 if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor)) )
c26873c8 1905 editor = wxPGEditor_ChoiceAndButton;
1c4293cb
VZ
1906
1907 // TextCtrl -> ComboBox
1908 else if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlEditor)) )
c26873c8 1909 editor = wxPGEditor_ComboBox;
1c4293cb
VZ
1910 }
1911
1912 return editor;
1913}
1914
1c4293cb
VZ
1915bool wxPGProperty::HasVisibleChildren() const
1916{
1917 unsigned int i;
1918
1919 for ( i=0; i<GetChildCount(); i++ )
1920 {
1921 wxPGProperty* child = Item(i);
1922
1923 if ( !child->HasFlag(wxPG_PROP_HIDDEN) )
1924 return true;
1925 }
1926
1927 return false;
1928}
1929
1c4293cb
VZ
1930bool wxPGProperty::RecreateEditor()
1931{
1932 wxPropertyGrid* pg = GetGrid();
1933 wxASSERT(pg);
1934
1935 wxPGProperty* selected = pg->GetSelection();
1936 if ( this == selected )
1937 {
1938 pg->DoSelectProperty(this, wxPG_SEL_FORCE);
1939 return true;
1940 }
1941 return false;
1942}
1943
1944
1945void wxPGProperty::SetValueImage( wxBitmap& bmp )
1946{
1947 delete m_valueBitmap;
1948
1949 if ( &bmp && bmp.Ok() )
1950 {
1951 // Resize the image
1952 wxSize maxSz = GetGrid()->GetImageSize();
1953 wxSize imSz(bmp.GetWidth(),bmp.GetHeight());
1954
4aee8334 1955 if ( imSz.y != maxSz.y )
1c4293cb
VZ
1956 {
1957 // Create a memory DC
1958 wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth());
1959
1960 wxMemoryDC dc;
1961 dc.SelectObject(*bmpNew);
1962
1963 // Scale
1964 // FIXME: This is ugly - use image or wait for scaling patch.
1c4293cb
VZ
1965 double scaleY = (double)maxSz.y / (double)imSz.y;
1966
4aee8334 1967 dc.SetUserScale(scaleY, scaleY);
1c4293cb 1968
4aee8334 1969 dc.DrawBitmap(bmp, 0, 0);
1c4293cb
VZ
1970
1971 m_valueBitmap = bmpNew;
1972 }
1973 else
1974 {
1975 m_valueBitmap = new wxBitmap(bmp);
1976 }
1977
1978 m_flags |= wxPG_PROP_CUSTOMIMAGE;
1979 }
1980 else
1981 {
1982 m_valueBitmap = NULL;
1983 m_flags &= ~(wxPG_PROP_CUSTOMIMAGE);
1984 }
1985}
1986
1987
1988wxPGProperty* wxPGProperty::GetMainParent() const
1989{
1990 const wxPGProperty* curChild = this;
1991 const wxPGProperty* curParent = m_parent;
1992
1993 while ( curParent && !curParent->IsCategory() )
1994 {
1995 curChild = curParent;
1996 curParent = curParent->m_parent;
1997 }
1998
1999 return (wxPGProperty*) curChild;
2000}
2001
2002
2003const wxPGProperty* wxPGProperty::GetLastVisibleSubItem() const
2004{
2005 //
2006 // Returns last visible sub-item, recursively.
2007 if ( !IsExpanded() || !GetChildCount() )
2008 return this;
2009
2010 return Last()->GetLastVisibleSubItem();
2011}
2012
2013
2014bool wxPGProperty::IsVisible() const
2015{
2016 const wxPGProperty* parent;
2017
2018 if ( HasFlag(wxPG_PROP_HIDDEN) )
2019 return false;
2020
2021 for ( parent = GetParent(); parent != NULL; parent = parent->GetParent() )
2022 {
2023 if ( !parent->IsExpanded() || parent->HasFlag(wxPG_PROP_HIDDEN) )
2024 return false;
2025 }
2026
2027 return true;
2028}
2029
2030wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const
2031{
2032 wxPropertyGridPageState* state = GetParentState();
e777bd14
JS
2033 if ( !state )
2034 return NULL;
1c4293cb
VZ
2035 wxPropertyGrid* propGrid = state->GetGrid();
2036 if ( state == propGrid->GetState() )
2037 return propGrid;
2038 return NULL;
2039}
2040
2041
2042int wxPGProperty::GetY2( int lh ) const
2043{
2044 const wxPGProperty* parent;
2045 const wxPGProperty* child = this;
2046
2047 int y = 0;
2048
2049 for ( parent = GetParent(); parent != NULL; parent = child->GetParent() )
2050 {
2051 if ( !parent->IsExpanded() )
2052 return -1;
2053 y += parent->GetChildrenHeight(lh, child->GetIndexInParent());
2054 y += lh;
2055 child = parent;
2056 }
2057
2058 y -= lh; // need to reduce one level
2059
2060 return y;
2061}
2062
2063
2064int wxPGProperty::GetY() const
2065{
2066 return GetY2(GetGrid()->GetRowHeight());
2067}
2068
1c4293cb 2069// This is used by Insert etc.
48a32cf6
JS
2070void wxPGProperty::DoAddChild( wxPGProperty* prop, int index,
2071 bool correct_mode )
1c4293cb 2072{
f7a094e1 2073 if ( index < 0 || (size_t)index >= m_children.size() )
1c4293cb 2074 {
f7a094e1
JS
2075 if ( correct_mode ) prop->m_arrIndex = m_children.size();
2076 m_children.push_back( prop );
1c4293cb
VZ
2077 }
2078 else
2079 {
f7a094e1 2080 m_children.insert( m_children.begin()+index, prop);
1b895132 2081 if ( correct_mode ) FixIndicesOfChildren( index );
1c4293cb
VZ
2082 }
2083
2084 prop->m_parent = this;
2085}
2086
48a32cf6 2087void wxPGProperty::DoPreAddChild( int index, wxPGProperty* prop )
1c4293cb 2088{
d665918b 2089 wxASSERT_MSG( prop->GetBaseName().length(),
48a32cf6
JS
2090 "Property's children must have unique, non-empty "
2091 "names within their scope" );
d665918b 2092
48a32cf6
JS
2093 prop->m_arrIndex = index;
2094 m_children.insert( m_children.begin()+index,
2095 prop );
1c4293cb
VZ
2096
2097 int custImgHeight = prop->OnMeasureImage().y;
2098 if ( custImgHeight < 0 /*|| custImgHeight > 1*/ )
2099 prop->m_flags |= wxPG_PROP_CUSTOMIMAGE;
2100
2101 prop->m_parent = this;
2102}
2103
48a32cf6
JS
2104void wxPGProperty::AddPrivateChild( wxPGProperty* prop )
2105{
2106 if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) )
2107 SetParentalType(wxPG_PROP_AGGREGATE);
2108
2109 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
2110 wxPG_PROP_AGGREGATE,
2111 "Do not mix up AddPrivateChild() calls with other "
2112 "property adders." );
2113
2114 DoPreAddChild( m_children.size(), prop );
2115}
2116
2117#if wxPG_COMPATIBILITY_1_4
2118void wxPGProperty::AddChild( wxPGProperty* prop )
2119{
2120 AddPrivateChild(prop);
2121}
2122#endif
2123
2124wxPGProperty* wxPGProperty::InsertChild( int index,
2125 wxPGProperty* childProperty )
2126{
2127 if ( index < 0 )
2128 index = m_children.size();
2129
2130 if ( m_parentState )
2131 {
2132 m_parentState->DoInsert(this, index, childProperty);
2133 }
2134 else
2135 {
2136 if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) )
2137 SetParentalType(wxPG_PROP_MISC_PARENT);
2138
2139 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
2140 wxPG_PROP_MISC_PARENT,
2141 "Do not mix up AddPrivateChild() calls with other "
2142 "property adders." );
2143
2144 DoPreAddChild( index, childProperty );
2145 }
2146
2147 return childProperty;
2148}
2149
d8c74d04
JS
2150void wxPGProperty::RemoveChild( wxPGProperty* p )
2151{
2152 wxArrayPGProperty::iterator it;
2153 wxArrayPGProperty& children = m_children;
2154
2155 for ( it=children.begin(); it != children.end(); it++ )
2156 {
2157 if ( *it == p )
2158 {
3ba703f9 2159 children.erase(it);
d8c74d04
JS
2160 break;
2161 }
2162 }
2163}
1c4293cb
VZ
2164
2165void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const
2166{
2167 wxASSERT( GetChildCount() );
2168 wxASSERT( !IsCategory() );
2169
2170 *value = GetValue();
2171
2172 if ( !list.GetCount() )
2173 return;
2174
2175 wxASSERT( GetChildCount() >= (unsigned int)list.GetCount() );
2176
2177 bool allChildrenSpecified;
2178
2179 // Don't fully update aggregate properties unless all children have
2180 // specified value
2181 if ( HasFlag(wxPG_PROP_AGGREGATE) )
2182 allChildrenSpecified = AreAllChildrenSpecified(&list);
2183 else
2184 allChildrenSpecified = true;
2185
2186 wxVariant childValue = list[0];
2187 unsigned int i;
2188 unsigned int n = 0;
2189
d665918b 2190 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
1c4293cb
VZ
2191
2192 for ( i=0; i<GetChildCount(); i++ )
2193 {
2194 const wxPGProperty* child = Item(i);
2195
d665918b 2196 if ( childValue.GetName() == child->GetBaseName() )
1c4293cb
VZ
2197 {
2198 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2199
0372d42e 2200 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2201 {
2202 wxVariant cv2(child->GetValue());
2203 child->AdaptListToValue(childValue, &cv2);
2204 childValue = cv2;
2205 }
2206
2207 if ( allChildrenSpecified )
b8b1ff48
JS
2208 {
2209 *value = ChildChanged(*value, i, childValue);
2210 }
2211
1c4293cb
VZ
2212 n++;
2213 if ( n == (unsigned int)list.GetCount() )
2214 break;
2215 childValue = list[n];
2216 }
2217 }
2218}
2219
2220
1b895132 2221void wxPGProperty::FixIndicesOfChildren( unsigned int starthere )
1c4293cb
VZ
2222{
2223 size_t i;
2224 for ( i=starthere;i<GetChildCount();i++)
2225 Item(i)->m_arrIndex = i;
2226}
2227
2228
2229// Returns (direct) child property with given name (or NULL if not found)
2230wxPGProperty* wxPGProperty::GetPropertyByName( const wxString& name ) const
2231{
2232 size_t i;
2233
2234 for ( i=0; i<GetChildCount(); i++ )
2235 {
2236 wxPGProperty* p = Item(i);
2237 if ( p->m_name == name )
2238 return p;
2239 }
2240
2241 // Does it have point, then?
2242 int pos = name.Find(wxS('.'));
2243 if ( pos <= 0 )
d3b9f782 2244 return NULL;
1c4293cb
VZ
2245
2246 wxPGProperty* p = GetPropertyByName(name. substr(0,pos));
2247
2248 if ( !p || !p->GetChildCount() )
2249 return NULL;
2250
2251 return p->GetPropertyByName(name.substr(pos+1,name.length()-pos-1));
2252}
2253
d665918b 2254wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const
1c4293cb
VZ
2255{
2256 unsigned int i = hintIndex;
2257
2258 if ( i >= GetChildCount() )
2259 i = 0;
2260
2261 unsigned int lastIndex = i - 1;
2262
2263 if ( lastIndex >= GetChildCount() )
2264 lastIndex = GetChildCount() - 1;
2265
2266 for (;;)
2267 {
2268 wxPGProperty* p = Item(i);
d665918b 2269 if ( p->m_name == name )
1c4293cb
VZ
2270 return p;
2271
2272 if ( i == lastIndex )
2273 break;
2274
2275 i++;
2276 if ( i == GetChildCount() )
2277 i = 0;
2278 };
2279
2280 return NULL;
2281}
2282
2283int wxPGProperty::GetChildrenHeight( int lh, int iMax_ ) const
2284{
2285 // Returns height of children, recursively, and
2286 // by taking expanded/collapsed status into account.
2287 //
2288 // iMax is used when finding property y-positions.
2289 //
2290 unsigned int i = 0;
2291 int h = 0;
2292
2293 if ( iMax_ == -1 )
2294 iMax_ = GetChildCount();
2295
2296 unsigned int iMax = iMax_;
2297
2298 wxASSERT( iMax <= GetChildCount() );
2299
2300 if ( !IsExpanded() && GetParent() )
2301 return 0;
2302
2303 while ( i < iMax )
2304 {
2305 wxPGProperty* pwc = (wxPGProperty*) Item(i);
2306
2307 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2308 {
2309 if ( !pwc->IsExpanded() ||
2310 pwc->GetChildCount() == 0 )
2311 h += lh;
2312 else
2313 h += pwc->GetChildrenHeight(lh) + lh;
2314 }
2315
2316 i++;
2317 }
2318
2319 return h;
2320}
2321
14bac4b5
JS
2322wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y,
2323 unsigned int lh,
2324 unsigned int* nextItemY ) const
1c4293cb
VZ
2325{
2326 wxASSERT( nextItemY );
2327
2328 // Linear search at the moment
2329 //
2330 // nextItemY = y of next visible property, final value will be written back.
2331 wxPGProperty* result = NULL;
2332 wxPGProperty* current = NULL;
2333 unsigned int iy = *nextItemY;
2334 unsigned int i = 0;
2335 unsigned int iMax = GetChildCount();
2336
2337 while ( i < iMax )
2338 {
2339 wxPGProperty* pwc = Item(i);
2340
2341 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2342 {
2343 // Found?
2344 if ( y < iy )
2345 {
2346 result = current;
2347 break;
2348 }
2349
2350 iy += lh;
2351
2352 if ( pwc->IsExpanded() &&
2353 pwc->GetChildCount() > 0 )
2354 {
2355 result = (wxPGProperty*) pwc->GetItemAtY( y, lh, &iy );
2356 if ( result )
2357 break;
2358 }
2359
2360 current = pwc;
2361 }
2362
2363 i++;
2364 }
2365
2366 // Found?
2367 if ( !result && y < iy )
2368 result = current;
2369
2370 *nextItemY = iy;
2371
2372 /*
2373 if ( current )
43b2d5e7 2374 {
1c4293cb 2375 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
43b2d5e7 2376 }
1c4293cb 2377 else
43b2d5e7 2378 {
1c4293cb 2379 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
43b2d5e7 2380 }
1c4293cb
VZ
2381 */
2382
2383 return (wxPGProperty*) result;
2384}
2385
2386void wxPGProperty::Empty()
2387{
2388 size_t i;
2389 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES) )
2390 {
2391 for ( i=0; i<GetChildCount(); i++ )
2392 {
f7a094e1 2393 delete m_children[i];
1c4293cb
VZ
2394 }
2395 }
2396
f7a094e1 2397 m_children.clear();
1c4293cb
VZ
2398}
2399
14bac4b5
JS
2400wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y ) const
2401{
2402 unsigned int nextItem;
2403 return GetItemAtY( y, GetGrid()->GetRowHeight(), &nextItem);
2404}
2405
91c818f8
JS
2406void wxPGProperty::DeleteChildren()
2407{
2408 wxPropertyGridPageState* state = m_parentState;
2409
2410 while ( GetChildCount() )
2411 {
2412 wxPGProperty* child = Item(GetChildCount()-1);
2413 state->DoDelete(child, true);
2414 }
2415}
2416
b8b1ff48
JS
2417wxVariant wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
2418 int WXUNUSED(childIndex),
2419 wxVariant& WXUNUSED(childValue) ) const
1c4293cb 2420{
b8b1ff48 2421 return wxNullVariant;
1c4293cb
VZ
2422}
2423
2424bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const
2425{
2426 unsigned int i;
2427
2428 const wxVariantList* pList = NULL;
2429 wxVariantList::const_iterator node;
2430
2431 if ( pendingList )
2432 {
2433 pList = &pendingList->GetList();
2434 node = pList->begin();
2435 }
2436
1c4293cb
VZ
2437 for ( i=0; i<GetChildCount(); i++ )
2438 {
2439 wxPGProperty* child = Item(i);
2440 const wxVariant* listValue = NULL;
2441 wxVariant value;
2442
2443 if ( pendingList )
2444 {
d665918b 2445 const wxString& childName = child->GetBaseName();
1c4293cb 2446
b7bc9d80 2447 for ( ; node != pList->end(); ++node )
1c4293cb
VZ
2448 {
2449 const wxVariant& item = *((const wxVariant*)*node);
d665918b 2450 if ( item.GetName() == childName )
1c4293cb
VZ
2451 {
2452 listValue = &item;
2453 value = item;
2454 break;
2455 }
2456 }
2457 }
2458
2459 if ( !listValue )
2460 value = child->GetValue();
2461
2462 if ( value.IsNull() )
2463 return false;
2464
2465 // Check recursively
2466 if ( child->GetChildCount() )
2467 {
2468 const wxVariant* childList = NULL;
2469
0372d42e 2470 if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2471 childList = listValue;
2472
2473 if ( !child->AreAllChildrenSpecified((wxVariant*)childList) )
2474 return false;
2475 }
2476 }
2477
2478 return true;
2479}
2480
2481wxPGProperty* wxPGProperty::UpdateParentValues()
2482{
2483 wxPGProperty* parent = m_parent;
2484 if ( parent && parent->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
2485 !parent->IsCategory() && !parent->IsRoot() )
2486 {
2487 wxString s;
c82a80e8 2488 parent->DoGenerateComposedValue(s);
1c4293cb
VZ
2489 parent->m_value = s;
2490 return parent->UpdateParentValues();
2491 }
2492 return this;
2493}
2494
2495bool wxPGProperty::IsTextEditable() const
2496{
2497 if ( HasFlag(wxPG_PROP_READONLY) )
2498 return false;
2499
2500 if ( HasFlag(wxPG_PROP_NOEDITOR) &&
2501 (GetChildCount() ||
2502 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2503 )
2504 return false;
2505
2506 return true;
2507}
2508
1c4293cb
VZ
2509// Call after fixed sub-properties added/removed after creation.
2510// if oldSelInd >= 0 and < new max items, then selection is
2511// moved to it. Note: oldSelInd -2 indicates that this property
2512// should be selected.
2513void wxPGProperty::SubPropsChanged( int oldSelInd )
2514{
2515 wxPropertyGridPageState* state = GetParentState();
2516 wxPropertyGrid* grid = state->GetGrid();
2517
2fd4a524
JS
2518 //
2519 // Re-repare children (recursively)
2520 for ( unsigned int i=0; i<GetChildCount(); i++ )
2521 {
2522 wxPGProperty* child = Item(i);
2523 child->InitAfterAdded(state, grid);
2524 }
1c4293cb 2525
d3b9f782 2526 wxPGProperty* sel = NULL;
f7a094e1
JS
2527 if ( oldSelInd >= (int)m_children.size() )
2528 oldSelInd = (int)m_children.size() - 1;
1c4293cb
VZ
2529
2530 if ( oldSelInd >= 0 )
f7a094e1 2531 sel = m_children[oldSelInd];
1c4293cb
VZ
2532 else if ( oldSelInd == -2 )
2533 sel = this;
2534
2535 if ( sel )
2536 state->DoSelectProperty(sel);
2537
2538 if ( state == grid->GetState() )
2539 {
2540 grid->GetPanel()->Refresh();
2541 }
2542}
2543
2544// -----------------------------------------------------------------------
2545// wxPGRootProperty
2546// -----------------------------------------------------------------------
2547
2548WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2549IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2550
2551
94b8ecf1 2552wxPGRootProperty::wxPGRootProperty( const wxString& name )
1c4293cb
VZ
2553 : wxPGProperty()
2554{
94b8ecf1
JS
2555 m_name = name;
2556 m_label = m_name;
1c4293cb
VZ
2557 SetParentalType(0);
2558 m_depth = 0;
2559}
2560
2561
2562wxPGRootProperty::~wxPGRootProperty()
2563{
2564}
2565
2566
2567// -----------------------------------------------------------------------
2568// wxPropertyCategory
2569// -----------------------------------------------------------------------
2570
2571WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2572IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2573
2574void wxPropertyCategory::Init()
2575{
2576 // don't set colour - prepareadditem method should do this
2577 SetParentalType(wxPG_PROP_CATEGORY);
2578 m_capFgColIndex = 1;
2579 m_textExtent = -1;
2580}
2581
2582wxPropertyCategory::wxPropertyCategory()
2583 : wxPGProperty()
2584{
2585 Init();
2586}
2587
2588
2589wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2590 : wxPGProperty(label,name)
2591{
2592 Init();
2593}
2594
2595
2596wxPropertyCategory::~wxPropertyCategory()
2597{
2598}
2599
2600
1425eca5
JS
2601wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value),
2602 int WXUNUSED(argFlags) ) const
1c4293cb
VZ
2603{
2604 return wxEmptyString;
2605}
2606
2607int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const
2608{
2609 if ( m_textExtent > 0 )
2610 return m_textExtent;
2611 int x = 0, y = 0;
03647350 2612 ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font );
1c4293cb
VZ
2613 return x;
2614}
2615
2616void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font )
2617{
2618 int x = 0, y = 0;
03647350 2619 wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font );
1c4293cb
VZ
2620 m_textExtent = x;
2621}
2622
2728c3bf
JS
2623// -----------------------------------------------------------------------
2624// wxPGChoices
2625// -----------------------------------------------------------------------
2626
2627wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, int value )
2628{
2629 AllocExclusive();
2630
2631 wxPGChoiceEntry entry(label, value);
2632 return m_data->Insert( -1, entry );
2633}
2634
2635// -----------------------------------------------------------------------
2636
2637wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, const wxBitmap& bitmap, int value )
2638{
2639 AllocExclusive();
2640
2641 wxPGChoiceEntry entry(label, value);
2642 entry.SetBitmap(bitmap);
2643 return m_data->Insert( -1, entry );
2644}
2645
2646// -----------------------------------------------------------------------
2647
2648wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index )
2649{
2650 AllocExclusive();
2651
2652 return m_data->Insert( index, entry );
2653}
2654
2655// -----------------------------------------------------------------------
2656
2657wxPGChoiceEntry& wxPGChoices::Insert( const wxString& label, int index, int value )
2658{
2659 AllocExclusive();
2660
2661 wxPGChoiceEntry entry(label, value);
2662 return m_data->Insert( index, entry );
2663}
2664
2665// -----------------------------------------------------------------------
2666
2667wxPGChoiceEntry& wxPGChoices::AddAsSorted( const wxString& label, int value )
2668{
2669 AllocExclusive();
2670
2671 size_t index = 0;
2672
2673 while ( index < GetCount() )
2674 {
2675 int cmpRes = GetLabel(index).Cmp(label);
2676 if ( cmpRes > 0 )
2677 break;
2678 index++;
2679 }
2680
2681 wxPGChoiceEntry entry(label, value);
2682 return m_data->Insert( index, entry );
2683}
2684
2685// -----------------------------------------------------------------------
2686
a243da29 2687void wxPGChoices::Add( const wxChar* const* labels, const ValArrItem* values )
2728c3bf
JS
2688{
2689 AllocExclusive();
2690
2691 unsigned int itemcount = 0;
a243da29 2692 const wxChar* const* p = &labels[0];
2728c3bf
JS
2693 while ( *p ) { p++; itemcount++; }
2694
2695 unsigned int i;
2696 for ( i = 0; i < itemcount; i++ )
2697 {
2698 int value = i;
2699 if ( values )
2700 value = values[i];
2701 wxPGChoiceEntry entry(labels[i], value);
2702 m_data->Insert( i, entry );
2703 }
2704}
2705
2706// -----------------------------------------------------------------------
2707
2708void wxPGChoices::Add( const wxArrayString& arr, const wxArrayInt& arrint )
2709{
2710 AllocExclusive();
2711
2712 unsigned int i;
2713 unsigned int itemcount = arr.size();
2714
2715 for ( i = 0; i < itemcount; i++ )
2716 {
2717 int value = i;
2718 if ( &arrint && arrint.size() )
2719 value = arrint[i];
2720 wxPGChoiceEntry entry(arr[i], value);
2721 m_data->Insert( i, entry );
2722 }
2723}
2724
2725// -----------------------------------------------------------------------
2726
2727void wxPGChoices::RemoveAt(size_t nIndex, size_t count)
2728{
2729 AllocExclusive();
2730
92ffc98a 2731 wxASSERT( m_data->GetRefCount() != -1 );
2728c3bf
JS
2732 m_data->m_items.erase(m_data->m_items.begin()+nIndex,
2733 m_data->m_items.begin()+nIndex+count);
2734}
2735
2736// -----------------------------------------------------------------------
2737
2738void wxPGChoices::Clear()
2739{
2740 if ( m_data != wxPGChoicesEmptyData )
2741 {
2742 AllocExclusive();
2743 m_data->Clear();
2744 }
2745}
2746
2747// -----------------------------------------------------------------------
2748
2749int wxPGChoices::Index( const wxString& str ) const
2750{
2751 if ( IsOk() )
2752 {
2753 unsigned int i;
2754 for ( i=0; i< m_data->GetCount(); i++ )
2755 {
2756 const wxPGChoiceEntry& entry = m_data->Item(i);
2757 if ( entry.HasText() && entry.GetText() == str )
2758 return i;
2759 }
2760 }
2761 return -1;
2762}
2763
2764// -----------------------------------------------------------------------
2765
2766int wxPGChoices::Index( int val ) const
2767{
2768 if ( IsOk() )
2769 {
2770 unsigned int i;
2771 for ( i=0; i< m_data->GetCount(); i++ )
2772 {
2773 const wxPGChoiceEntry& entry = m_data->Item(i);
2774 if ( entry.GetValue() == val )
2775 return i;
2776 }
2777 }
2778 return -1;
2779}
2780
2781// -----------------------------------------------------------------------
2782
2783wxArrayString wxPGChoices::GetLabels() const
2784{
2785 wxArrayString arr;
2786 unsigned int i;
2787
2788 if ( this && IsOk() )
2789 for ( i=0; i<GetCount(); i++ )
2790 arr.push_back(GetLabel(i));
2791
2792 return arr;
2793}
2794
2795// -----------------------------------------------------------------------
2796
2797wxArrayInt wxPGChoices::GetValuesForStrings( const wxArrayString& strings ) const
2798{
2799 wxArrayInt arr;
2800
2801 if ( IsOk() )
2802 {
2803 unsigned int i;
2804 for ( i=0; i< strings.size(); i++ )
2805 {
2806 int index = Index(strings[i]);
2807 if ( index >= 0 )
2808 arr.Add(GetValue(index));
2809 else
2810 arr.Add(wxPG_INVALID_VALUE);
2811 }
2812 }
2813
2814 return arr;
2815}
2816
2817// -----------------------------------------------------------------------
2818
2819wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings,
2820 wxArrayString* unmatched ) const
2821{
2822 wxArrayInt arr;
2823
2824 if ( IsOk() )
2825 {
2826 unsigned int i;
2827 for ( i=0; i< strings.size(); i++ )
2828 {
2829 const wxString& str = strings[i];
2830 int index = Index(str);
2831 if ( index >= 0 )
2832 arr.Add(index);
2833 else if ( unmatched )
2834 unmatched->Add(str);
2835 }
2836 }
2837
2838 return arr;
2839}
2840
2841// -----------------------------------------------------------------------
2842
2843void wxPGChoices::AllocExclusive()
2844{
2845 EnsureData();
2846
92ffc98a 2847 if ( m_data->GetRefCount() != 1 )
2728c3bf
JS
2848 {
2849 wxPGChoicesData* data = new wxPGChoicesData();
2850 data->CopyDataFrom(m_data);
2851 Free();
2852 m_data = data;
2853 }
2854}
2855
2856// -----------------------------------------------------------------------
2857
2858void wxPGChoices::AssignData( wxPGChoicesData* data )
2859{
2860 Free();
2861
2862 if ( data != wxPGChoicesEmptyData )
2863 {
2864 m_data = data;
92ffc98a 2865 data->IncRef();
2728c3bf
JS
2866 }
2867}
2868
2869// -----------------------------------------------------------------------
2870
2871void wxPGChoices::Init()
2872{
2873 m_data = wxPGChoicesEmptyData;
2874}
2875
2876// -----------------------------------------------------------------------
2877
2878void wxPGChoices::Free()
2879{
2880 if ( m_data != wxPGChoicesEmptyData )
2881 {
2882 m_data->DecRef();
2883 m_data = wxPGChoicesEmptyData;
2884 }
2885}
2886
1c4293cb
VZ
2887// -----------------------------------------------------------------------
2888// wxPGAttributeStorage
2889// -----------------------------------------------------------------------
2890
2891wxPGAttributeStorage::wxPGAttributeStorage()
2892{
2893}
2894
2895wxPGAttributeStorage::~wxPGAttributeStorage()
2896{
2897 wxPGHashMapS2P::iterator it;
2898
b7bc9d80 2899 for ( it = m_map.begin(); it != m_map.end(); ++it )
1c4293cb
VZ
2900 {
2901 wxVariantData* data = (wxVariantData*) it->second;
2902 data->DecRef();
2903 }
2904}
2905
2906void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value )
2907{
2908 wxVariantData* data = value.GetData();
2909
2910 // Free old, if any
2911 wxPGHashMapS2P::iterator it = m_map.find(name);
2912 if ( it != m_map.end() )
1802a91d 2913 {
1c4293cb
VZ
2914 ((wxVariantData*)it->second)->DecRef();
2915
1802a91d
JS
2916 if ( !data )
2917 {
2918 // If Null variant, just remove from set
2919 m_map.erase(it);
2920 return;
2921 }
2922 }
2923
1c4293cb 2924 if ( data )
1802a91d 2925 {
1c4293cb
VZ
2926 data->IncRef();
2927
1802a91d
JS
2928 m_map[name] = data;
2929 }
1c4293cb
VZ
2930}
2931
f4bc1aa2 2932#endif // wxUSE_PROPGRID