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