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