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