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