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