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