]> git.saurik.com Git - wxWidgets.git/blame - src/propgrid/property.cpp
Make it possible to use wxCharBuffer during program initialization.
[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) ||
1070 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1c4293cb 1071 {
f275b5db 1072 if ( len > 0 )
1c4293cb 1073 {
ae82388e
JS
1074 if ( child->StringToValue(variant, token,
1075 propagatedFlags|wxPG_COMPOSITE_FRAGMENT) )
1c4293cb 1076 {
ae82388e
JS
1077 // We really need to set the variant's name
1078 // *after* child->StringToValue() has been
1079 // called, since variant's value may be set by
1080 // assigning another variant into it, which
1081 // then usually causes name to be copied (ie.
1082 // usually cleared) as well. wxBoolProperty
1083 // being case in point with its use of
1084 // wxPGVariant_Bool macro as an optimization.
1085 variant.SetName(childName);
f275b5db 1086 list.Append(variant);
1c4293cb 1087
f275b5db
JS
1088 changed = true;
1089 }
1090 }
1091 else
1092 {
1093 // Empty, becomes unspecified
1094 variant.MakeNull();
ae82388e 1095 variant.SetName(childName);
f275b5db 1096 list.Append(variant);
1c4293cb
VZ
1097 changed = true;
1098 }
1099 }
1c4293cb
VZ
1100
1101 curChild++;
1102 if ( curChild >= iMax )
1103 break;
1104 }
1105
1106 tokenStart = 0xFFFFFF;
1107 }
1108 }
1109 else
1110 {
1111 // Token is not running
1112 if ( a != wxS(' ') )
1113 {
1114
1115 addOnlyIfNotEmpty = false;
1116
1117 // Is this a group of tokens?
1118 if ( a == wxS('[') )
1119 {
1120 int depth = 1;
1121
b7bc9d80 1122 if ( it != text.end() ) ++it;
1c4293cb
VZ
1123 pos++;
1124 size_t startPos = pos;
1125
1126 // Group item - find end
1127 while ( it != text.end() && depth > 0 )
1128 {
1129 a = *it;
b7bc9d80 1130 ++it;
1c4293cb
VZ
1131 pos++;
1132
1133 if ( a == wxS(']') )
1134 depth--;
1135 else if ( a == wxS('[') )
1136 depth++;
1137 }
1138
1139 token = text.substr(startPos,pos-startPos-1);
1140
1141 if ( !token.length() )
1142 break;
1143
1144 const wxPGProperty* child = Item(curChild);
1145
2bbd3749
JS
1146 wxVariant oldChildValue = child->GetValue();
1147 wxVariant variant(oldChildValue);
f275b5db
JS
1148
1149 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
1150 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1c4293cb 1151 {
a64a1bf7
JS
1152 wxString childName = child->GetBaseName();
1153
1154 bool stvRes = child->StringToValue( variant, token,
1155 propagatedFlags );
f275b5db
JS
1156 if ( stvRes || (variant != oldChildValue) )
1157 {
a64a1bf7
JS
1158 variant.SetName(childName);
1159 list.Append(variant);
1160
1161 changed = true;
f275b5db
JS
1162 }
1163 else
1164 {
a64a1bf7 1165 // No changes...
f275b5db 1166 }
1c4293cb
VZ
1167 }
1168
1169 curChild++;
1170 if ( curChild >= iMax )
1171 break;
1172
1173 addOnlyIfNotEmpty = true;
1174
1175 tokenStart = 0xFFFFFF;
1176 }
1177 else
1178 {
1179 tokenStart = pos;
1180
1181 if ( a == delimeter )
a64a1bf7 1182 strPosIncrement -= 1;
1c4293cb
VZ
1183 }
1184 }
1185 }
1186
1187 if ( a == 0 )
1188 break;
1189
a64a1bf7
JS
1190 it += strPosIncrement;
1191
1c4293cb
VZ
1192 if ( it != text.end() )
1193 {
1194 a = *it;
1195 }
1196 else
1197 {
1198 a = 0;
1199 }
a64a1bf7
JS
1200
1201 pos += strPosIncrement;
1c4293cb
VZ
1202 }
1203
1204 if ( changed )
1205 variant = list;
1206
1207 return changed;
1208}
1209
1210bool wxPGProperty::SetValueFromString( const wxString& text, int argFlags )
1211{
1212 wxVariant variant(m_value);
1213 bool res = StringToValue(variant, text, argFlags);
1214 if ( res )
1215 SetValue(variant);
1216 return res;
1217}
1218
1219bool wxPGProperty::SetValueFromInt( long number, int argFlags )
1220{
1221 wxVariant variant(m_value);
1222 bool res = IntToValue(variant, number, argFlags);
1223 if ( res )
1224 SetValue(variant);
1225 return res;
1226}
1227
1228wxSize wxPGProperty::OnMeasureImage( int WXUNUSED(item) ) const
1229{
1230 if ( m_valueBitmap )
1231 return wxSize(m_valueBitmap->GetWidth(),-1);
1232
1233 return wxSize(0,0);
1234}
1235
4aee8334
JS
1236int wxPGProperty::GetImageOffset( int imageWidth ) const
1237{
1238 int imageOffset = 0;
1239
1240 if ( imageWidth )
1241 {
1242 // Do not increment offset too much for wide images
1243 if ( imageWidth <= (wxPG_CUSTOM_IMAGE_WIDTH+5) )
1244 imageOffset = imageWidth + DEFAULT_IMAGE_OFFSET_INCREMENT;
1245 else
1246 imageOffset = imageWidth + 1;
1247 }
1248
1249 return imageOffset;
1250}
1251
1c4293cb
VZ
1252wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const
1253{
1254 return wxPGGlobalVars->m_defaultRenderer;
1255}
1256
1257void wxPGProperty::OnCustomPaint( wxDC& dc,
1258 const wxRect& rect,
1259 wxPGPaintData& )
1260{
1261 wxBitmap* bmp = m_valueBitmap;
1262
1263 wxCHECK_RET( bmp && bmp->Ok(), wxT("invalid bitmap") );
1264
1265 wxCHECK_RET( rect.x >= 0, wxT("unexpected measure call") );
1266
1267 dc.DrawBitmap(*bmp,rect.x,rect.y);
1268}
1269
1270const wxPGEditor* wxPGProperty::DoGetEditorClass() const
1271{
c26873c8 1272 return wxPGEditor_TextCtrl;
1c4293cb
VZ
1273}
1274
1275// Default extra property event handling - that is, none at all.
1276bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& )
1277{
1278 return false;
1279}
1280
1281
1282void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags )
1283{
104837f2
JS
1284 // If auto unspecified values are not wanted (via window or property style),
1285 // then get default value instead of wxNullVariant.
1286 if ( value.IsNull() && (flags & wxPG_SETVAL_BY_USER) &&
1287 !UsesAutoUnspecified() )
1288 {
1289 value = GetDefaultValue();
1290 }
1291
1c4293cb
VZ
1292 if ( !value.IsNull() )
1293 {
8f18b252
JS
1294 wxVariant tempListVariant;
1295
1c4293cb
VZ
1296 SetCommonValue(-1);
1297 // List variants are reserved a special purpose
1298 // as intermediate containers for child values
1299 // of properties with children.
0372d42e 1300 if ( value.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb 1301 {
8f18b252
JS
1302 //
1303 // However, situation is different for composed string properties
1304 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
1305 {
1306 tempListVariant = value;
1307 pList = &tempListVariant;
1308 }
1309
1c4293cb
VZ
1310 wxVariant newValue;
1311 AdaptListToValue(value, &newValue);
1312 value = newValue;
1313 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1314 }
1315
1316 if ( HasFlag( wxPG_PROP_AGGREGATE) )
1317 flags |= wxPG_SETVAL_AGGREGATED;
1318
1319 if ( pList && !pList->IsNull() )
1320 {
0372d42e 1321 wxASSERT( pList->GetType() == wxPG_VARIANT_TYPE_LIST );
1c4293cb
VZ
1322 wxASSERT( GetChildCount() );
1323 wxASSERT( !IsCategory() );
1324
1325 wxVariantList& list = pList->GetList();
1326 wxVariantList::iterator node;
1327 unsigned int i = 0;
1328
1329 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1330
1331 // Children in list can be in any order, but we will give hint to
d665918b 1332 // GetPropertyByNameWH(). This optimizes for full list parsing.
b7bc9d80 1333 for ( node = list.begin(); node != list.end(); ++node )
1c4293cb
VZ
1334 {
1335 wxVariant& childValue = *((wxVariant*)*node);
d665918b 1336 wxPGProperty* child = GetPropertyByNameWH(childValue.GetName(), i);
1c4293cb
VZ
1337 if ( child )
1338 {
d665918b 1339 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
0372d42e 1340 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
1341 {
1342 if ( child->HasFlag(wxPG_PROP_AGGREGATE) && !(flags & wxPG_SETVAL_AGGREGATED) )
1343 {
1344 wxVariant listRefCopy = childValue;
1345 child->SetValue(childValue, &listRefCopy, flags|wxPG_SETVAL_FROM_PARENT);
1346 }
1347 else
1348 {
1349 wxVariant oldVal = child->GetValue();
1350 child->SetValue(oldVal, &childValue, flags|wxPG_SETVAL_FROM_PARENT);
1351 }
1352 }
0372d42e 1353 else if ( child->GetValue() != childValue )
1c4293cb
VZ
1354 {
1355 // For aggregate properties, we will trust RefreshChildren()
1356 // to update child values.
1357 if ( !HasFlag(wxPG_PROP_AGGREGATE) )
1358 child->SetValue(childValue, NULL, flags|wxPG_SETVAL_FROM_PARENT);
8f18b252
JS
1359 if ( flags & wxPG_SETVAL_BY_USER )
1360 child->SetFlag(wxPG_PROP_MODIFIED);
1c4293cb
VZ
1361 }
1362 }
1363 i++;
1364 }
1365 }
1366
1367 if ( !value.IsNull() )
1368 {
0372d42e 1369 m_value = value;
1c4293cb 1370 OnSetValue();
1c4293cb
VZ
1371 }
1372
8f18b252 1373 if ( flags & wxPG_SETVAL_BY_USER )
1c4293cb
VZ
1374 SetFlag(wxPG_PROP_MODIFIED);
1375
1376 if ( HasFlag(wxPG_PROP_AGGREGATE) )
1377 RefreshChildren();
1378 }
1379 else
1380 {
1381 if ( m_commonValue != -1 )
1382 {
1383 wxPropertyGrid* pg = GetGrid();
1384 if ( !pg || m_commonValue != pg->GetUnspecifiedCommonValue() )
1385 SetCommonValue(-1);
1386 }
1387
1388 m_value = value;
1389
1390 // Set children to unspecified, but only if aggregate or
1391 // value is <composed>
1392 if ( AreChildrenComponents() )
1393 {
1394 unsigned int i;
1395 for ( i=0; i<GetChildCount(); i++ )
1396 Item(i)->SetValue(value, NULL, flags|wxPG_SETVAL_FROM_PARENT);
1397 }
1398 }
1399
daeb4e4d
JS
1400 if ( !(flags & wxPG_SETVAL_FROM_PARENT) )
1401 UpdateParentValues();
1402
1c4293cb 1403 //
5ff90676 1404 // Update editor control.
1c4293cb 1405 if ( flags & wxPG_SETVAL_REFRESH_EDITOR )
e777bd14 1406 {
e777bd14
JS
1407 wxPropertyGrid* pg = GetGridIfDisplayed();
1408 if ( pg )
5ff90676
JS
1409 {
1410 wxPGProperty* selected = pg->GetSelectedProperty();
1411
1412 // Only refresh the control if this was selected, or
1413 // this was some parent of selected, or vice versa)
1414 if ( selected && (selected == this ||
1415 selected->IsSomeParent(this) ||
1416 this->IsSomeParent(selected)) )
1417 RefreshEditor();
1418
e777bd14 1419 pg->DrawItemAndValueRelated(this);
5ff90676 1420 }
e777bd14 1421 }
1c4293cb
VZ
1422}
1423
1424
1425void wxPGProperty::SetValueInEvent( wxVariant value ) const
1426{
1427 GetGrid()->ValueChangeInEvent(value);
1428}
1429
1430void wxPGProperty::SetFlagRecursively( FlagType flag, bool set )
1431{
d58526d5 1432 ChangeFlag(flag, set);
1c4293cb
VZ
1433
1434 unsigned int i;
1435 for ( i = 0; i < GetChildCount(); i++ )
1436 Item(i)->SetFlagRecursively(flag, set);
1437}
1438
1439void wxPGProperty::RefreshEditor()
1440{
f521bae6
JS
1441 if ( !m_parent )
1442 return;
1c4293cb 1443
f521bae6
JS
1444 wxPropertyGrid* pg = GetGrid();
1445 if ( pg && pg->GetSelectedProperty() == this )
a6353fe8 1446 pg->RefreshEditor();
f521bae6 1447}
1c4293cb
VZ
1448
1449wxVariant wxPGProperty::GetDefaultValue() const
1450{
0ce8e27f 1451 wxVariant defVal = GetAttribute(wxPG_ATTR_DEFAULT_VALUE);
1c4293cb
VZ
1452 if ( !defVal.IsNull() )
1453 return defVal;
1454
1455 wxVariant value = GetValue();
1456
1457 if ( !value.IsNull() )
1458 {
0372d42e
JS
1459 wxString valueType(value.GetType());
1460
1461 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1c4293cb 1462 return wxPGVariant_Zero;
0372d42e 1463 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1c4293cb 1464 return wxPGVariant_EmptyString;
0372d42e 1465 if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1c4293cb 1466 return wxPGVariant_False;
0372d42e 1467 if ( valueType == wxPG_VARIANT_TYPE_DOUBLE )
1c4293cb 1468 return wxVariant(0.0);
0372d42e 1469 if ( valueType == wxPG_VARIANT_TYPE_ARRSTRING )
1c4293cb 1470 return wxVariant(wxArrayString());
0372d42e
JS
1471 if ( valueType == wxS("wxLongLong") )
1472 return WXVARIANT(wxLongLong(0));
1473 if ( valueType == wxS("wxULongLong") )
1474 return WXVARIANT(wxULongLong(0));
1475 if ( valueType == wxS("wxColour") )
1476 return WXVARIANT(*wxBLACK);
1c4293cb 1477#if wxUSE_DATETIME
0372d42e 1478 if ( valueType == wxPG_VARIANT_TYPE_DATETIME )
1c4293cb
VZ
1479 return wxVariant(wxDateTime::Now());
1480#endif
0372d42e
JS
1481 if ( valueType == wxS("wxFont") )
1482 return WXVARIANT(*wxNORMAL_FONT);
1483 if ( valueType == wxS("wxPoint") )
1484 return WXVARIANT(wxPoint(0, 0));
1485 if ( valueType == wxS("wxSize") )
1486 return WXVARIANT(wxSize(0, 0));
1c4293cb
VZ
1487 }
1488
1489 return wxVariant();
1490}
1491
d7e2b522
JS
1492void wxPGProperty::EnsureCells( unsigned int column )
1493{
1494 if ( column >= m_cells.size() )
1495 {
1496 // Fill empty slots with default cells
1497 wxPropertyGrid* pg = GetGrid();
1498 wxPGCell defaultCell;
1499
521f1d83
JS
1500 // Work around possible VC6 bug by using intermediate variables
1501 const wxPGCell& propDefCell = pg->GetPropertyDefaultCell();
1502 const wxPGCell& catDefCell = pg->GetCategoryDefaultCell();
1503
d7e2b522 1504 if ( !HasFlag(wxPG_PROP_CATEGORY) )
521f1d83 1505 defaultCell = propDefCell;
d7e2b522 1506 else
521f1d83 1507 defaultCell = catDefCell;
d7e2b522
JS
1508
1509 // TODO: Replace with resize() call
1510 unsigned int cellCountMax = column+1;
1511
1512 for ( unsigned int i=m_cells.size(); i<cellCountMax; i++ )
1513 m_cells.push_back(defaultCell);
1514 }
1515}
1516
1517void wxPGProperty::SetCell( int column,
1518 const wxPGCell& cell )
1519{
1520 EnsureCells(column);
1521
1522 m_cells[column] = cell;
1523}
1524
1525void wxPGProperty::AdaptiveSetCell( unsigned int firstCol,
1526 unsigned int lastCol,
1527 const wxPGCell& cell,
1528 const wxPGCell& srcData,
1529 wxPGCellData* unmodCellData,
1530 FlagType ignoreWithFlags,
1531 bool recursively )
1532{
1533 //
1534 // Sets cell in memory optimizing fashion. That is, if
1535 // current cell data matches unmodCellData, we will
1536 // simply get reference to data from cell. Otherwise,
1537 // cell information from srcData is merged into current.
1538 //
1539
1540 if ( !(m_flags & ignoreWithFlags) && !IsRoot() )
1541 {
1542 EnsureCells(lastCol);
1543
1544 for ( unsigned int col=firstCol; col<=lastCol; col++ )
1545 {
1546 if ( m_cells[col].GetData() == unmodCellData )
1547 {
1548 // Data matches... use cell directly
1549 m_cells[col] = cell;
1550 }
1551 else
1552 {
1553 // Data did not match... merge valid information
1554 m_cells[col].MergeFrom(srcData);
1555 }
1556 }
1557 }
1558
1559 if ( recursively )
1560 {
1561 for ( unsigned int i=0; i<GetChildCount(); i++ )
1562 Item(i)->AdaptiveSetCell( firstCol,
1563 lastCol,
1564 cell,
1565 srcData,
1566 unmodCellData,
1567 ignoreWithFlags,
1568 recursively );
1569 }
1570}
1571
1572const wxPGCell& wxPGProperty::GetCell( unsigned int column ) const
1c4293cb 1573{
d7e2b522
JS
1574 if ( m_cells.size() > column )
1575 return m_cells[column];
1576
1577 wxPropertyGrid* pg = GetGrid();
1578
1579 if ( IsCategory() )
1580 return pg->GetCategoryDefaultCell();
1581
1582 return pg->GetPropertyDefaultCell();
1583}
1584
58935d4a 1585wxPGCell& wxPGProperty::GetOrCreateCell( unsigned int column )
d7e2b522
JS
1586{
1587 EnsureCells(column);
1588 return m_cells[column];
1589}
1590
1591void wxPGProperty::SetBackgroundColour( const wxColour& colour,
e607eac2 1592 int flags )
d7e2b522
JS
1593{
1594 wxPGProperty* firstProp = this;
e607eac2 1595 bool recursively = flags & wxPG_RECURSE ? true : false;
d7e2b522
JS
1596
1597 //
1598 // If category is tried to set recursively, skip it and only
1599 // affect the children.
1600 if ( recursively )
1601 {
1602 while ( firstProp->IsCategory() )
1603 {
1604 if ( !firstProp->GetChildCount() )
1605 return;
1606 firstProp = firstProp->Item(0);
1607 }
1608 }
1609
1610 wxPGCell& firstCell = firstProp->GetCell(0);
1611 wxPGCellData* firstCellData = firstCell.GetData();
1612
1613 wxPGCell newCell(firstCell);
1614 newCell.SetBgCol(colour);
1615 wxPGCell srcCell;
1616 srcCell.SetBgCol(colour);
1617
1618 AdaptiveSetCell( 0,
1619 GetParentState()->GetColumnCount()-1,
1620 newCell,
1621 srcCell,
1622 firstCellData,
1623 recursively ? wxPG_PROP_CATEGORY : 0,
1624 recursively );
1625}
1626
1627void wxPGProperty::SetTextColour( const wxColour& colour,
e607eac2 1628 int flags )
d7e2b522
JS
1629{
1630 wxPGProperty* firstProp = this;
e607eac2 1631 bool recursively = flags & wxPG_RECURSE ? true : false;
d7e2b522
JS
1632
1633 //
1634 // If category is tried to set recursively, skip it and only
1635 // affect the children.
1636 if ( recursively )
1637 {
1638 while ( firstProp->IsCategory() )
1639 {
1640 if ( !firstProp->GetChildCount() )
1641 return;
1642 firstProp = firstProp->Item(0);
1643 }
1644 }
1c4293cb 1645
d7e2b522
JS
1646 wxPGCell& firstCell = firstProp->GetCell(0);
1647 wxPGCellData* firstCellData = firstCell.GetData();
1648
1649 wxPGCell newCell(firstCell);
1650 newCell.SetFgCol(colour);
1651 wxPGCell srcCell;
1652 srcCell.SetFgCol(colour);
1653
1654 AdaptiveSetCell( 0,
1655 GetParentState()->GetColumnCount()-1,
1656 newCell,
1657 srcCell,
1658 firstCellData,
1659 recursively ? wxPG_PROP_CATEGORY : 0,
1660 recursively );
1c4293cb
VZ
1661}
1662
1c4293cb
VZ
1663wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const
1664{
1665 return NULL;
1666}
1667
1668bool wxPGProperty::DoSetAttribute( const wxString& WXUNUSED(name), wxVariant& WXUNUSED(value) )
1669{
1670 return false;
1671}
1672
1673void wxPGProperty::SetAttribute( const wxString& name, wxVariant value )
1674{
1675 if ( DoSetAttribute( name, value ) )
1676 {
1677 // Support working without grid, when possible
1678 if ( wxPGGlobalVars->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES ) )
1679 return;
1680 }
1681
1682 m_attributes.Set( name, value );
1683}
1684
1685void wxPGProperty::SetAttributes( const wxPGAttributeStorage& attributes )
1686{
1687 wxPGAttributeStorage::const_iterator it = attributes.StartIteration();
1688 wxVariant variant;
1689
1690 while ( attributes.GetNext(it, variant) )
1691 SetAttribute( variant.GetName(), variant );
1692}
1693
1694wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
1695{
1696 return wxVariant();
1697}
1698
1699
1700wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
1701{
1702 return m_attributes.FindValue(name);
1703}
1704
1705wxString wxPGProperty::GetAttribute( const wxString& name, const wxString& defVal ) const
1706{
1707 wxVariant variant = m_attributes.FindValue(name);
1708
1709 if ( !variant.IsNull() )
1710 return variant.GetString();
1711
1712 return defVal;
1713}
1714
1715long wxPGProperty::GetAttributeAsLong( const wxString& name, long defVal ) const
1716{
1717 wxVariant variant = m_attributes.FindValue(name);
1718
4e00b908
JS
1719 if ( variant.IsNull() )
1720 return defVal;
1721
1722 return variant.GetLong();
1c4293cb
VZ
1723}
1724
1725double wxPGProperty::GetAttributeAsDouble( const wxString& name, double defVal ) const
1726{
1c4293cb
VZ
1727 wxVariant variant = m_attributes.FindValue(name);
1728
4e00b908
JS
1729 if ( variant.IsNull() )
1730 return defVal;
1c4293cb 1731
4e00b908 1732 return variant.GetDouble();
1c4293cb
VZ
1733}
1734
1735wxVariant wxPGProperty::GetAttributesAsList() const
1736{
1737 wxVariantList tempList;
1738 wxVariant v( tempList, wxString::Format(wxS("@%s@attr"),m_name.c_str()) );
1739
1740 wxPGAttributeStorage::const_iterator it = m_attributes.StartIteration();
1741 wxVariant variant;
1742
1743 while ( m_attributes.GetNext(it, variant) )
1744 v.Append(variant);
1745
1746 return v;
1747}
1748
1749// Slots of utility flags are NULL
1750const unsigned int gs_propFlagToStringSize = 14;
1751
a243da29 1752static const wxChar* const gs_propFlagToString[gs_propFlagToStringSize] = {
1c4293cb
VZ
1753 NULL,
1754 wxT("DISABLED"),
1755 wxT("HIDDEN"),
1756 NULL,
1757 wxT("NOEDITOR"),
1758 wxT("COLLAPSED"),
1759 NULL,
1760 NULL,
1761 NULL,
1762 NULL,
1763 NULL,
1764 NULL,
1765 NULL,
1766 NULL
1767};
1768
1769wxString wxPGProperty::GetFlagsAsString( FlagType flagsMask ) const
1770{
1771 wxString s;
1772 int relevantFlags = m_flags & flagsMask & wxPG_STRING_STORED_FLAGS;
1773 FlagType a = 1;
1774
1775 unsigned int i = 0;
1776 for ( i=0; i<gs_propFlagToStringSize; i++ )
1777 {
1778 if ( relevantFlags & a )
1779 {
1780 const wxChar* fs = gs_propFlagToString[i];
1781 wxASSERT(fs);
1782 if ( s.length() )
1783 s << wxS("|");
1784 s << fs;
1785 }
1786 a = a << 1;
1787 }
1788
1789 return s;
1790}
1791
1792void wxPGProperty::SetFlagsFromString( const wxString& str )
1793{
1794 FlagType flags = 0;
1795
1796 WX_PG_TOKENIZER1_BEGIN(str, wxS('|'))
1797 unsigned int i;
1798 for ( i=0; i<gs_propFlagToStringSize; i++ )
1799 {
1800 const wxChar* fs = gs_propFlagToString[i];
1801 if ( fs && str == fs )
1802 {
1803 flags |= (1<<i);
1804 break;
1805 }
1806 }
1807 WX_PG_TOKENIZER1_END()
1808
1809 m_flags = (m_flags & ~wxPG_STRING_STORED_FLAGS) | flags;
1810}
1811
1812wxValidator* wxPGProperty::DoGetValidator() const
1813{
d3b9f782 1814 return NULL;
1c4293cb
VZ
1815}
1816
939d9364 1817int wxPGProperty::InsertChoice( const wxString& label, int index, int value )
1c4293cb 1818{
939d9364
JS
1819 wxPropertyGrid* pg = GetGrid();
1820 int sel = GetChoiceSelection();
1821
1822 int newSel = sel;
1823
1824 if ( index == wxNOT_FOUND )
1825 index = m_choices.GetCount();
1826
1827 if ( index <= sel )
1828 newSel++;
1829
1830 m_choices.Insert(label, index, value);
1831
1832 if ( sel != newSel )
1833 SetChoiceSelection(newSel);
1834
1835 if ( this == pg->GetSelection() )
1836 GetEditorClass()->InsertItem(pg->GetEditorControl(),label,index);
1837
1838 return index;
1c4293cb
VZ
1839}
1840
939d9364
JS
1841
1842void wxPGProperty::DeleteChoice( int index )
1c4293cb 1843{
939d9364
JS
1844 wxPropertyGrid* pg = GetGrid();
1845
1846 int sel = GetChoiceSelection();
1847 int newSel = sel;
1848
1849 // Adjust current value
1850 if ( sel == index )
1851 {
1852 SetValueToUnspecified();
1853 newSel = 0;
1854 }
1855 else if ( index < sel )
1856 {
1857 newSel--;
1858 }
1859
1860 m_choices.RemoveAt(index);
1861
1862 if ( sel != newSel )
1863 SetChoiceSelection(newSel);
1864
1865 if ( this == pg->GetSelection() )
1866 GetEditorClass()->DeleteItem(pg->GetEditorControl(), index);
1c4293cb
VZ
1867}
1868
939d9364 1869int wxPGProperty::GetChoiceSelection() const
1c4293cb 1870{
939d9364
JS
1871 wxVariant value = GetValue();
1872 wxString valueType = value.GetType();
1873 int index = wxNOT_FOUND;
1874
1875 if ( IsValueUnspecified() || !m_choices.GetCount() )
1876 return wxNOT_FOUND;
1877
1878 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1879 {
1880 index = value.GetLong();
1881 }
1882 else if ( valueType == wxPG_VARIANT_TYPE_STRING )
1883 {
1884 index = m_choices.Index(value.GetString());
1885 }
1886 else if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1887 {
1888 index = value.GetBool()? 1 : 0;
1889 }
1890
1891 return index;
1c4293cb
VZ
1892}
1893
939d9364 1894void wxPGProperty::SetChoiceSelection( int newValue )
1c4293cb 1895{
939d9364
JS
1896 // Changes value of a property with choices, but only
1897 // works if the value type is long or string.
1898 wxString valueType = GetValue().GetType();
1899
1900 wxCHECK_RET( m_choices.IsOk(), wxT("invalid choiceinfo") );
1c4293cb 1901
939d9364
JS
1902 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1903 {
1904 SetValue( m_choices.GetLabel(newValue) );
1905 }
1906 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1907 {
1908 SetValue( (long) newValue );
1909 }
1c4293cb
VZ
1910}
1911
1912bool wxPGProperty::SetChoices( wxPGChoices& choices )
1913{
26b22ae3
JS
1914 // Property must be de-selected first (otherwise choices in
1915 // the control would be de-synced with true choices)
1916 wxPropertyGrid* pg = GetGrid();
1917 if ( pg && pg->GetSelection() == this )
1918 pg->ClearSelection();
1919
939d9364 1920 m_choices.Assign(choices);
1c4293cb 1921
1c4293cb 1922 {
939d9364
JS
1923 // This may be needed to trigger some initialization
1924 // (but don't do it if property is somewhat uninitialized)
1925 wxVariant defVal = GetDefaultValue();
1926 if ( defVal.IsNull() )
1927 return false;
1c4293cb 1928
939d9364 1929 SetValue(defVal);
1c4293cb 1930 }
939d9364
JS
1931
1932 return true;
1c4293cb
VZ
1933}
1934
1935
1936const wxPGEditor* wxPGProperty::GetEditorClass() const
1937{
1938 const wxPGEditor* editor;
1939
1940 if ( !m_customEditor )
1941 {
1942 editor = DoGetEditorClass();
1943 }
1944 else
1945 editor = m_customEditor;
1946
1947 //
1948 // Maybe override editor if common value specified
1949 if ( GetDisplayedCommonValueCount() )
1950 {
1951 // TextCtrlAndButton -> ComboBoxAndButton
1952 if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor)) )
c26873c8 1953 editor = wxPGEditor_ChoiceAndButton;
1c4293cb
VZ
1954
1955 // TextCtrl -> ComboBox
1956 else if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlEditor)) )
c26873c8 1957 editor = wxPGEditor_ComboBox;
1c4293cb
VZ
1958 }
1959
1960 return editor;
1961}
1962
1c4293cb
VZ
1963bool wxPGProperty::HasVisibleChildren() const
1964{
1965 unsigned int i;
1966
1967 for ( i=0; i<GetChildCount(); i++ )
1968 {
1969 wxPGProperty* child = Item(i);
1970
1971 if ( !child->HasFlag(wxPG_PROP_HIDDEN) )
1972 return true;
1973 }
1974
1975 return false;
1976}
1977
1c4293cb
VZ
1978bool wxPGProperty::RecreateEditor()
1979{
1980 wxPropertyGrid* pg = GetGrid();
1981 wxASSERT(pg);
1982
1983 wxPGProperty* selected = pg->GetSelection();
1984 if ( this == selected )
1985 {
1986 pg->DoSelectProperty(this, wxPG_SEL_FORCE);
1987 return true;
1988 }
1989 return false;
1990}
1991
1992
1993void wxPGProperty::SetValueImage( wxBitmap& bmp )
1994{
1995 delete m_valueBitmap;
1996
1997 if ( &bmp && bmp.Ok() )
1998 {
1999 // Resize the image
2000 wxSize maxSz = GetGrid()->GetImageSize();
2001 wxSize imSz(bmp.GetWidth(),bmp.GetHeight());
2002
4aee8334 2003 if ( imSz.y != maxSz.y )
1c4293cb
VZ
2004 {
2005 // Create a memory DC
2006 wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth());
2007
2008 wxMemoryDC dc;
2009 dc.SelectObject(*bmpNew);
2010
2011 // Scale
2012 // FIXME: This is ugly - use image or wait for scaling patch.
1c4293cb
VZ
2013 double scaleY = (double)maxSz.y / (double)imSz.y;
2014
4aee8334 2015 dc.SetUserScale(scaleY, scaleY);
1c4293cb 2016
4aee8334 2017 dc.DrawBitmap(bmp, 0, 0);
1c4293cb
VZ
2018
2019 m_valueBitmap = bmpNew;
2020 }
2021 else
2022 {
2023 m_valueBitmap = new wxBitmap(bmp);
2024 }
2025
2026 m_flags |= wxPG_PROP_CUSTOMIMAGE;
2027 }
2028 else
2029 {
2030 m_valueBitmap = NULL;
2031 m_flags &= ~(wxPG_PROP_CUSTOMIMAGE);
2032 }
2033}
2034
2035
2036wxPGProperty* wxPGProperty::GetMainParent() const
2037{
2038 const wxPGProperty* curChild = this;
2039 const wxPGProperty* curParent = m_parent;
2040
2041 while ( curParent && !curParent->IsCategory() )
2042 {
2043 curChild = curParent;
2044 curParent = curParent->m_parent;
2045 }
2046
2047 return (wxPGProperty*) curChild;
2048}
2049
2050
2051const wxPGProperty* wxPGProperty::GetLastVisibleSubItem() const
2052{
2053 //
2054 // Returns last visible sub-item, recursively.
2055 if ( !IsExpanded() || !GetChildCount() )
2056 return this;
2057
2058 return Last()->GetLastVisibleSubItem();
2059}
2060
2061
2062bool wxPGProperty::IsVisible() const
2063{
2064 const wxPGProperty* parent;
2065
2066 if ( HasFlag(wxPG_PROP_HIDDEN) )
2067 return false;
2068
2069 for ( parent = GetParent(); parent != NULL; parent = parent->GetParent() )
2070 {
2071 if ( !parent->IsExpanded() || parent->HasFlag(wxPG_PROP_HIDDEN) )
2072 return false;
2073 }
2074
2075 return true;
2076}
2077
2078wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const
2079{
2080 wxPropertyGridPageState* state = GetParentState();
e777bd14
JS
2081 if ( !state )
2082 return NULL;
1c4293cb
VZ
2083 wxPropertyGrid* propGrid = state->GetGrid();
2084 if ( state == propGrid->GetState() )
2085 return propGrid;
2086 return NULL;
2087}
2088
2089
2090int wxPGProperty::GetY2( int lh ) const
2091{
2092 const wxPGProperty* parent;
2093 const wxPGProperty* child = this;
2094
2095 int y = 0;
2096
2097 for ( parent = GetParent(); parent != NULL; parent = child->GetParent() )
2098 {
2099 if ( !parent->IsExpanded() )
2100 return -1;
2101 y += parent->GetChildrenHeight(lh, child->GetIndexInParent());
2102 y += lh;
2103 child = parent;
2104 }
2105
2106 y -= lh; // need to reduce one level
2107
2108 return y;
2109}
2110
2111
2112int wxPGProperty::GetY() const
2113{
2114 return GetY2(GetGrid()->GetRowHeight());
2115}
2116
1c4293cb 2117// This is used by Insert etc.
48a32cf6
JS
2118void wxPGProperty::DoAddChild( wxPGProperty* prop, int index,
2119 bool correct_mode )
1c4293cb 2120{
f7a094e1 2121 if ( index < 0 || (size_t)index >= m_children.size() )
1c4293cb 2122 {
f7a094e1
JS
2123 if ( correct_mode ) prop->m_arrIndex = m_children.size();
2124 m_children.push_back( prop );
1c4293cb
VZ
2125 }
2126 else
2127 {
f7a094e1 2128 m_children.insert( m_children.begin()+index, prop);
1b895132 2129 if ( correct_mode ) FixIndicesOfChildren( index );
1c4293cb
VZ
2130 }
2131
2132 prop->m_parent = this;
2133}
2134
48a32cf6 2135void wxPGProperty::DoPreAddChild( int index, wxPGProperty* prop )
1c4293cb 2136{
d665918b 2137 wxASSERT_MSG( prop->GetBaseName().length(),
48a32cf6
JS
2138 "Property's children must have unique, non-empty "
2139 "names within their scope" );
d665918b 2140
48a32cf6
JS
2141 prop->m_arrIndex = index;
2142 m_children.insert( m_children.begin()+index,
2143 prop );
1c4293cb
VZ
2144
2145 int custImgHeight = prop->OnMeasureImage().y;
2146 if ( custImgHeight < 0 /*|| custImgHeight > 1*/ )
2147 prop->m_flags |= wxPG_PROP_CUSTOMIMAGE;
2148
2149 prop->m_parent = this;
2150}
2151
48a32cf6
JS
2152void wxPGProperty::AddPrivateChild( wxPGProperty* prop )
2153{
2154 if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) )
2155 SetParentalType(wxPG_PROP_AGGREGATE);
2156
2157 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
2158 wxPG_PROP_AGGREGATE,
2159 "Do not mix up AddPrivateChild() calls with other "
2160 "property adders." );
2161
2162 DoPreAddChild( m_children.size(), prop );
2163}
2164
2165#if wxPG_COMPATIBILITY_1_4
2166void wxPGProperty::AddChild( wxPGProperty* prop )
2167{
2168 AddPrivateChild(prop);
2169}
2170#endif
2171
2172wxPGProperty* wxPGProperty::InsertChild( int index,
2173 wxPGProperty* childProperty )
2174{
2175 if ( index < 0 )
2176 index = m_children.size();
2177
2178 if ( m_parentState )
2179 {
2180 m_parentState->DoInsert(this, index, childProperty);
2181 }
2182 else
2183 {
2184 if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) )
2185 SetParentalType(wxPG_PROP_MISC_PARENT);
2186
2187 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
2188 wxPG_PROP_MISC_PARENT,
2189 "Do not mix up AddPrivateChild() calls with other "
2190 "property adders." );
2191
2192 DoPreAddChild( index, childProperty );
2193 }
2194
2195 return childProperty;
2196}
2197
d8c74d04
JS
2198void wxPGProperty::RemoveChild( wxPGProperty* p )
2199{
2200 wxArrayPGProperty::iterator it;
2201 wxArrayPGProperty& children = m_children;
2202
2203 for ( it=children.begin(); it != children.end(); it++ )
2204 {
2205 if ( *it == p )
2206 {
3ba703f9 2207 children.erase(it);
d8c74d04
JS
2208 break;
2209 }
2210 }
2211}
1c4293cb
VZ
2212
2213void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const
2214{
2215 wxASSERT( GetChildCount() );
2216 wxASSERT( !IsCategory() );
2217
2218 *value = GetValue();
2219
2220 if ( !list.GetCount() )
2221 return;
2222
2223 wxASSERT( GetChildCount() >= (unsigned int)list.GetCount() );
2224
2225 bool allChildrenSpecified;
2226
2227 // Don't fully update aggregate properties unless all children have
2228 // specified value
2229 if ( HasFlag(wxPG_PROP_AGGREGATE) )
2230 allChildrenSpecified = AreAllChildrenSpecified(&list);
2231 else
2232 allChildrenSpecified = true;
2233
2234 wxVariant childValue = list[0];
2235 unsigned int i;
2236 unsigned int n = 0;
2237
d665918b 2238 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
1c4293cb
VZ
2239
2240 for ( i=0; i<GetChildCount(); i++ )
2241 {
2242 const wxPGProperty* child = Item(i);
2243
d665918b 2244 if ( childValue.GetName() == child->GetBaseName() )
1c4293cb
VZ
2245 {
2246 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2247
0372d42e 2248 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2249 {
2250 wxVariant cv2(child->GetValue());
2251 child->AdaptListToValue(childValue, &cv2);
2252 childValue = cv2;
2253 }
2254
2255 if ( allChildrenSpecified )
b8b1ff48
JS
2256 {
2257 *value = ChildChanged(*value, i, childValue);
2258 }
2259
1c4293cb
VZ
2260 n++;
2261 if ( n == (unsigned int)list.GetCount() )
2262 break;
2263 childValue = list[n];
2264 }
2265 }
2266}
2267
2268
1b895132 2269void wxPGProperty::FixIndicesOfChildren( unsigned int starthere )
1c4293cb
VZ
2270{
2271 size_t i;
2272 for ( i=starthere;i<GetChildCount();i++)
2273 Item(i)->m_arrIndex = i;
2274}
2275
2276
2277// Returns (direct) child property with given name (or NULL if not found)
2278wxPGProperty* wxPGProperty::GetPropertyByName( const wxString& name ) const
2279{
2280 size_t i;
2281
2282 for ( i=0; i<GetChildCount(); i++ )
2283 {
2284 wxPGProperty* p = Item(i);
2285 if ( p->m_name == name )
2286 return p;
2287 }
2288
2289 // Does it have point, then?
2290 int pos = name.Find(wxS('.'));
2291 if ( pos <= 0 )
d3b9f782 2292 return NULL;
1c4293cb
VZ
2293
2294 wxPGProperty* p = GetPropertyByName(name. substr(0,pos));
2295
2296 if ( !p || !p->GetChildCount() )
2297 return NULL;
2298
2299 return p->GetPropertyByName(name.substr(pos+1,name.length()-pos-1));
2300}
2301
d665918b 2302wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const
1c4293cb
VZ
2303{
2304 unsigned int i = hintIndex;
2305
2306 if ( i >= GetChildCount() )
2307 i = 0;
2308
2309 unsigned int lastIndex = i - 1;
2310
2311 if ( lastIndex >= GetChildCount() )
2312 lastIndex = GetChildCount() - 1;
2313
2314 for (;;)
2315 {
2316 wxPGProperty* p = Item(i);
d665918b 2317 if ( p->m_name == name )
1c4293cb
VZ
2318 return p;
2319
2320 if ( i == lastIndex )
2321 break;
2322
2323 i++;
2324 if ( i == GetChildCount() )
2325 i = 0;
2326 };
2327
2328 return NULL;
2329}
2330
2331int wxPGProperty::GetChildrenHeight( int lh, int iMax_ ) const
2332{
2333 // Returns height of children, recursively, and
2334 // by taking expanded/collapsed status into account.
2335 //
2336 // iMax is used when finding property y-positions.
2337 //
2338 unsigned int i = 0;
2339 int h = 0;
2340
2341 if ( iMax_ == -1 )
2342 iMax_ = GetChildCount();
2343
2344 unsigned int iMax = iMax_;
2345
2346 wxASSERT( iMax <= GetChildCount() );
2347
2348 if ( !IsExpanded() && GetParent() )
2349 return 0;
2350
2351 while ( i < iMax )
2352 {
2353 wxPGProperty* pwc = (wxPGProperty*) Item(i);
2354
2355 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2356 {
2357 if ( !pwc->IsExpanded() ||
2358 pwc->GetChildCount() == 0 )
2359 h += lh;
2360 else
2361 h += pwc->GetChildrenHeight(lh) + lh;
2362 }
2363
2364 i++;
2365 }
2366
2367 return h;
2368}
2369
14bac4b5
JS
2370wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y,
2371 unsigned int lh,
2372 unsigned int* nextItemY ) const
1c4293cb
VZ
2373{
2374 wxASSERT( nextItemY );
2375
2376 // Linear search at the moment
2377 //
2378 // nextItemY = y of next visible property, final value will be written back.
2379 wxPGProperty* result = NULL;
2380 wxPGProperty* current = NULL;
2381 unsigned int iy = *nextItemY;
2382 unsigned int i = 0;
2383 unsigned int iMax = GetChildCount();
2384
2385 while ( i < iMax )
2386 {
2387 wxPGProperty* pwc = Item(i);
2388
2389 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2390 {
2391 // Found?
2392 if ( y < iy )
2393 {
2394 result = current;
2395 break;
2396 }
2397
2398 iy += lh;
2399
2400 if ( pwc->IsExpanded() &&
2401 pwc->GetChildCount() > 0 )
2402 {
2403 result = (wxPGProperty*) pwc->GetItemAtY( y, lh, &iy );
2404 if ( result )
2405 break;
2406 }
2407
2408 current = pwc;
2409 }
2410
2411 i++;
2412 }
2413
2414 // Found?
2415 if ( !result && y < iy )
2416 result = current;
2417
2418 *nextItemY = iy;
2419
2420 /*
2421 if ( current )
43b2d5e7 2422 {
1c4293cb 2423 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
43b2d5e7 2424 }
1c4293cb 2425 else
43b2d5e7 2426 {
1c4293cb 2427 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
43b2d5e7 2428 }
1c4293cb
VZ
2429 */
2430
2431 return (wxPGProperty*) result;
2432}
2433
2434void wxPGProperty::Empty()
2435{
2436 size_t i;
2437 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES) )
2438 {
2439 for ( i=0; i<GetChildCount(); i++ )
2440 {
f7a094e1 2441 delete m_children[i];
1c4293cb
VZ
2442 }
2443 }
2444
f7a094e1 2445 m_children.clear();
1c4293cb
VZ
2446}
2447
14bac4b5
JS
2448wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y ) const
2449{
2450 unsigned int nextItem;
2451 return GetItemAtY( y, GetGrid()->GetRowHeight(), &nextItem);
2452}
2453
91c818f8
JS
2454void wxPGProperty::DeleteChildren()
2455{
2456 wxPropertyGridPageState* state = m_parentState;
2457
2458 while ( GetChildCount() )
2459 {
2460 wxPGProperty* child = Item(GetChildCount()-1);
2461 state->DoDelete(child, true);
2462 }
2463}
2464
b8b1ff48
JS
2465wxVariant wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
2466 int WXUNUSED(childIndex),
2467 wxVariant& WXUNUSED(childValue) ) const
1c4293cb 2468{
b8b1ff48 2469 return wxNullVariant;
1c4293cb
VZ
2470}
2471
2472bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const
2473{
2474 unsigned int i;
2475
2476 const wxVariantList* pList = NULL;
2477 wxVariantList::const_iterator node;
2478
2479 if ( pendingList )
2480 {
2481 pList = &pendingList->GetList();
2482 node = pList->begin();
2483 }
2484
1c4293cb
VZ
2485 for ( i=0; i<GetChildCount(); i++ )
2486 {
2487 wxPGProperty* child = Item(i);
2488 const wxVariant* listValue = NULL;
2489 wxVariant value;
2490
2491 if ( pendingList )
2492 {
d665918b 2493 const wxString& childName = child->GetBaseName();
1c4293cb 2494
b7bc9d80 2495 for ( ; node != pList->end(); ++node )
1c4293cb
VZ
2496 {
2497 const wxVariant& item = *((const wxVariant*)*node);
d665918b 2498 if ( item.GetName() == childName )
1c4293cb
VZ
2499 {
2500 listValue = &item;
2501 value = item;
2502 break;
2503 }
2504 }
2505 }
2506
2507 if ( !listValue )
2508 value = child->GetValue();
2509
2510 if ( value.IsNull() )
2511 return false;
2512
2513 // Check recursively
2514 if ( child->GetChildCount() )
2515 {
2516 const wxVariant* childList = NULL;
2517
0372d42e 2518 if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2519 childList = listValue;
2520
2521 if ( !child->AreAllChildrenSpecified((wxVariant*)childList) )
2522 return false;
2523 }
2524 }
2525
2526 return true;
2527}
2528
2529wxPGProperty* wxPGProperty::UpdateParentValues()
2530{
2531 wxPGProperty* parent = m_parent;
2532 if ( parent && parent->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
2533 !parent->IsCategory() && !parent->IsRoot() )
2534 {
2535 wxString s;
c82a80e8 2536 parent->DoGenerateComposedValue(s);
1c4293cb
VZ
2537 parent->m_value = s;
2538 return parent->UpdateParentValues();
2539 }
2540 return this;
2541}
2542
2543bool wxPGProperty::IsTextEditable() const
2544{
2545 if ( HasFlag(wxPG_PROP_READONLY) )
2546 return false;
2547
2548 if ( HasFlag(wxPG_PROP_NOEDITOR) &&
2549 (GetChildCount() ||
2550 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2551 )
2552 return false;
2553
2554 return true;
2555}
2556
1c4293cb
VZ
2557// Call after fixed sub-properties added/removed after creation.
2558// if oldSelInd >= 0 and < new max items, then selection is
2559// moved to it. Note: oldSelInd -2 indicates that this property
2560// should be selected.
2561void wxPGProperty::SubPropsChanged( int oldSelInd )
2562{
2563 wxPropertyGridPageState* state = GetParentState();
2564 wxPropertyGrid* grid = state->GetGrid();
2565
2fd4a524
JS
2566 //
2567 // Re-repare children (recursively)
2568 for ( unsigned int i=0; i<GetChildCount(); i++ )
2569 {
2570 wxPGProperty* child = Item(i);
2571 child->InitAfterAdded(state, grid);
2572 }
1c4293cb 2573
d3b9f782 2574 wxPGProperty* sel = NULL;
f7a094e1
JS
2575 if ( oldSelInd >= (int)m_children.size() )
2576 oldSelInd = (int)m_children.size() - 1;
1c4293cb
VZ
2577
2578 if ( oldSelInd >= 0 )
f7a094e1 2579 sel = m_children[oldSelInd];
1c4293cb
VZ
2580 else if ( oldSelInd == -2 )
2581 sel = this;
2582
2583 if ( sel )
2584 state->DoSelectProperty(sel);
2585
2586 if ( state == grid->GetState() )
2587 {
2588 grid->GetPanel()->Refresh();
2589 }
2590}
2591
2592// -----------------------------------------------------------------------
2593// wxPGRootProperty
2594// -----------------------------------------------------------------------
2595
2596WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2597IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2598
2599
94b8ecf1 2600wxPGRootProperty::wxPGRootProperty( const wxString& name )
1c4293cb
VZ
2601 : wxPGProperty()
2602{
94b8ecf1
JS
2603 m_name = name;
2604 m_label = m_name;
1c4293cb
VZ
2605 SetParentalType(0);
2606 m_depth = 0;
2607}
2608
2609
2610wxPGRootProperty::~wxPGRootProperty()
2611{
2612}
2613
2614
2615// -----------------------------------------------------------------------
2616// wxPropertyCategory
2617// -----------------------------------------------------------------------
2618
2619WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2620IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2621
2622void wxPropertyCategory::Init()
2623{
2624 // don't set colour - prepareadditem method should do this
2625 SetParentalType(wxPG_PROP_CATEGORY);
2626 m_capFgColIndex = 1;
2627 m_textExtent = -1;
2628}
2629
2630wxPropertyCategory::wxPropertyCategory()
2631 : wxPGProperty()
2632{
2633 Init();
2634}
2635
2636
2637wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2638 : wxPGProperty(label,name)
2639{
2640 Init();
2641}
2642
2643
2644wxPropertyCategory::~wxPropertyCategory()
2645{
2646}
2647
2648
1425eca5
JS
2649wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value),
2650 int WXUNUSED(argFlags) ) const
1c4293cb 2651{
e16bff8e
JS
2652 if ( m_value.GetType() == wxPG_VARIANT_TYPE_STRING )
2653 return m_value.GetString();
1c4293cb
VZ
2654 return wxEmptyString;
2655}
2656
e16bff8e
JS
2657wxString wxPropertyCategory::GetValueAsString( int argFlags ) const
2658{
2659#if wxPG_COMPATIBILITY_1_4
2660 // This is backwards compatibility test
2661 // That is, to make sure this function is not overridden
2662 // (instead, ValueToString() should be).
2663 if ( argFlags == 0xFFFF )
2664 {
2665 // Do not override! (for backwards compliancy)
2666 return g_invalidStringContent;
2667 }
2668#endif
2669
2670 // Unspecified value is always empty string
2671 if ( IsValueUnspecified() )
2672 return wxEmptyString;
2673
2674 return wxPGProperty::GetValueAsString(argFlags);
2675}
2676
1c4293cb
VZ
2677int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const
2678{
2679 if ( m_textExtent > 0 )
2680 return m_textExtent;
2681 int x = 0, y = 0;
03647350 2682 ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font );
1c4293cb
VZ
2683 return x;
2684}
2685
2686void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font )
2687{
2688 int x = 0, y = 0;
03647350 2689 wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font );
1c4293cb
VZ
2690 m_textExtent = x;
2691}
2692
2728c3bf
JS
2693// -----------------------------------------------------------------------
2694// wxPGChoices
2695// -----------------------------------------------------------------------
2696
2697wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, int value )
2698{
2699 AllocExclusive();
2700
2701 wxPGChoiceEntry entry(label, value);
2702 return m_data->Insert( -1, entry );
2703}
2704
2705// -----------------------------------------------------------------------
2706
2707wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, const wxBitmap& bitmap, int value )
2708{
2709 AllocExclusive();
2710
2711 wxPGChoiceEntry entry(label, value);
2712 entry.SetBitmap(bitmap);
2713 return m_data->Insert( -1, entry );
2714}
2715
2716// -----------------------------------------------------------------------
2717
2718wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index )
2719{
2720 AllocExclusive();
2721
2722 return m_data->Insert( index, entry );
2723}
2724
2725// -----------------------------------------------------------------------
2726
2727wxPGChoiceEntry& wxPGChoices::Insert( const wxString& label, int index, int value )
2728{
2729 AllocExclusive();
2730
2731 wxPGChoiceEntry entry(label, value);
2732 return m_data->Insert( index, entry );
2733}
2734
2735// -----------------------------------------------------------------------
2736
2737wxPGChoiceEntry& wxPGChoices::AddAsSorted( const wxString& label, int value )
2738{
2739 AllocExclusive();
2740
2741 size_t index = 0;
2742
2743 while ( index < GetCount() )
2744 {
2745 int cmpRes = GetLabel(index).Cmp(label);
2746 if ( cmpRes > 0 )
2747 break;
2748 index++;
2749 }
2750
2751 wxPGChoiceEntry entry(label, value);
2752 return m_data->Insert( index, entry );
2753}
2754
2755// -----------------------------------------------------------------------
2756
a243da29 2757void wxPGChoices::Add( const wxChar* const* labels, const ValArrItem* values )
2728c3bf
JS
2758{
2759 AllocExclusive();
2760
2761 unsigned int itemcount = 0;
a243da29 2762 const wxChar* const* p = &labels[0];
2728c3bf
JS
2763 while ( *p ) { p++; itemcount++; }
2764
2765 unsigned int i;
2766 for ( i = 0; i < itemcount; i++ )
2767 {
2768 int value = i;
2769 if ( values )
2770 value = values[i];
2771 wxPGChoiceEntry entry(labels[i], value);
2772 m_data->Insert( i, entry );
2773 }
2774}
2775
2776// -----------------------------------------------------------------------
2777
2778void wxPGChoices::Add( const wxArrayString& arr, const wxArrayInt& arrint )
2779{
2780 AllocExclusive();
2781
2782 unsigned int i;
2783 unsigned int itemcount = arr.size();
2784
2785 for ( i = 0; i < itemcount; i++ )
2786 {
2787 int value = i;
2788 if ( &arrint && arrint.size() )
2789 value = arrint[i];
2790 wxPGChoiceEntry entry(arr[i], value);
2791 m_data->Insert( i, entry );
2792 }
2793}
2794
2795// -----------------------------------------------------------------------
2796
2797void wxPGChoices::RemoveAt(size_t nIndex, size_t count)
2798{
2799 AllocExclusive();
2800
92ffc98a 2801 wxASSERT( m_data->GetRefCount() != -1 );
2728c3bf
JS
2802 m_data->m_items.erase(m_data->m_items.begin()+nIndex,
2803 m_data->m_items.begin()+nIndex+count);
2804}
2805
2806// -----------------------------------------------------------------------
2807
2808void wxPGChoices::Clear()
2809{
2810 if ( m_data != wxPGChoicesEmptyData )
2811 {
2812 AllocExclusive();
2813 m_data->Clear();
2814 }
2815}
2816
2817// -----------------------------------------------------------------------
2818
2819int wxPGChoices::Index( const wxString& str ) const
2820{
2821 if ( IsOk() )
2822 {
2823 unsigned int i;
2824 for ( i=0; i< m_data->GetCount(); i++ )
2825 {
2826 const wxPGChoiceEntry& entry = m_data->Item(i);
2827 if ( entry.HasText() && entry.GetText() == str )
2828 return i;
2829 }
2830 }
2831 return -1;
2832}
2833
2834// -----------------------------------------------------------------------
2835
2836int wxPGChoices::Index( int val ) const
2837{
2838 if ( IsOk() )
2839 {
2840 unsigned int i;
2841 for ( i=0; i< m_data->GetCount(); i++ )
2842 {
2843 const wxPGChoiceEntry& entry = m_data->Item(i);
2844 if ( entry.GetValue() == val )
2845 return i;
2846 }
2847 }
2848 return -1;
2849}
2850
2851// -----------------------------------------------------------------------
2852
2853wxArrayString wxPGChoices::GetLabels() const
2854{
2855 wxArrayString arr;
2856 unsigned int i;
2857
2858 if ( this && IsOk() )
2859 for ( i=0; i<GetCount(); i++ )
2860 arr.push_back(GetLabel(i));
2861
2862 return arr;
2863}
2864
2865// -----------------------------------------------------------------------
2866
2867wxArrayInt wxPGChoices::GetValuesForStrings( const wxArrayString& strings ) const
2868{
2869 wxArrayInt arr;
2870
2871 if ( IsOk() )
2872 {
2873 unsigned int i;
2874 for ( i=0; i< strings.size(); i++ )
2875 {
2876 int index = Index(strings[i]);
2877 if ( index >= 0 )
2878 arr.Add(GetValue(index));
2879 else
2880 arr.Add(wxPG_INVALID_VALUE);
2881 }
2882 }
2883
2884 return arr;
2885}
2886
2887// -----------------------------------------------------------------------
2888
2889wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings,
2890 wxArrayString* unmatched ) const
2891{
2892 wxArrayInt arr;
2893
2894 if ( IsOk() )
2895 {
2896 unsigned int i;
2897 for ( i=0; i< strings.size(); i++ )
2898 {
2899 const wxString& str = strings[i];
2900 int index = Index(str);
2901 if ( index >= 0 )
2902 arr.Add(index);
2903 else if ( unmatched )
2904 unmatched->Add(str);
2905 }
2906 }
2907
2908 return arr;
2909}
2910
2911// -----------------------------------------------------------------------
2912
2913void wxPGChoices::AllocExclusive()
2914{
2915 EnsureData();
2916
92ffc98a 2917 if ( m_data->GetRefCount() != 1 )
2728c3bf
JS
2918 {
2919 wxPGChoicesData* data = new wxPGChoicesData();
2920 data->CopyDataFrom(m_data);
2921 Free();
2922 m_data = data;
2923 }
2924}
2925
2926// -----------------------------------------------------------------------
2927
2928void wxPGChoices::AssignData( wxPGChoicesData* data )
2929{
2930 Free();
2931
2932 if ( data != wxPGChoicesEmptyData )
2933 {
2934 m_data = data;
92ffc98a 2935 data->IncRef();
2728c3bf
JS
2936 }
2937}
2938
2939// -----------------------------------------------------------------------
2940
2941void wxPGChoices::Init()
2942{
2943 m_data = wxPGChoicesEmptyData;
2944}
2945
2946// -----------------------------------------------------------------------
2947
2948void wxPGChoices::Free()
2949{
2950 if ( m_data != wxPGChoicesEmptyData )
2951 {
2952 m_data->DecRef();
2953 m_data = wxPGChoicesEmptyData;
2954 }
2955}
2956
1c4293cb
VZ
2957// -----------------------------------------------------------------------
2958// wxPGAttributeStorage
2959// -----------------------------------------------------------------------
2960
2961wxPGAttributeStorage::wxPGAttributeStorage()
2962{
2963}
2964
2965wxPGAttributeStorage::~wxPGAttributeStorage()
2966{
2967 wxPGHashMapS2P::iterator it;
2968
b7bc9d80 2969 for ( it = m_map.begin(); it != m_map.end(); ++it )
1c4293cb
VZ
2970 {
2971 wxVariantData* data = (wxVariantData*) it->second;
2972 data->DecRef();
2973 }
2974}
2975
2976void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value )
2977{
2978 wxVariantData* data = value.GetData();
2979
2980 // Free old, if any
2981 wxPGHashMapS2P::iterator it = m_map.find(name);
2982 if ( it != m_map.end() )
1802a91d 2983 {
1c4293cb
VZ
2984 ((wxVariantData*)it->second)->DecRef();
2985
1802a91d
JS
2986 if ( !data )
2987 {
2988 // If Null variant, just remove from set
2989 m_map.erase(it);
2990 return;
2991 }
2992 }
2993
1c4293cb 2994 if ( data )
1802a91d 2995 {
1c4293cb
VZ
2996 data->IncRef();
2997
1802a91d
JS
2998 m_map[name] = data;
2999 }
1c4293cb
VZ
3000}
3001
f4bc1aa2 3002#endif // wxUSE_PROPGRID