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