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