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