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