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