cleanup: unreachable code, unused variables, indentation, etc
[wxWidgets.git] / src / propgrid / property.cpp
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 // RCS-ID: $Id$
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_PROPGRID
20
21 #ifndef WX_PRECOMP
22 #include "wx/defs.h"
23 #include "wx/object.h"
24 #include "wx/hash.h"
25 #include "wx/string.h"
26 #include "wx/log.h"
27 #include "wx/event.h"
28 #include "wx/window.h"
29 #include "wx/panel.h"
30 #include "wx/dc.h"
31 #include "wx/dcmemory.h"
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/propgrid/propgrid.h"
39
40
41 #define PWC_CHILD_SUMMARY_LIMIT 16 // Maximum number of children summarized in a parent property's
42 // value field.
43
44 #define PWC_CHILD_SUMMARY_CHAR_LIMIT 64 // Character limit of summary field when not editing
45
46 #if wxPG_COMPATIBILITY_1_4
47
48 // Used to establish backwards compatiblity
49 const char* g_invalidStringContent = "@__TOTALLY_INVALID_STRING__@";
50
51 #endif
52
53 // -----------------------------------------------------------------------
54
55 static void wxPGDrawFocusRect( wxDC& dc, const wxRect& rect )
56 {
57 #if defined(__WXMSW__) && !defined(__WXWINCE__)
58 // FIXME: Use DrawFocusRect code above (currently it draws solid line
59 // for caption focus but works ok for other stuff).
60 // Also, it seems that this code may not work in future wx versions.
61 dc.SetLogicalFunction(wxINVERT);
62
63 wxPen pen(*wxBLACK,1,wxDOT);
64 pen.SetCap(wxCAP_BUTT);
65 dc.SetPen(pen);
66 dc.SetBrush(*wxTRANSPARENT_BRUSH);
67
68 dc.DrawRectangle(rect);
69
70 dc.SetLogicalFunction(wxCOPY);
71 #else
72 dc.SetLogicalFunction(wxINVERT);
73
74 dc.SetPen(wxPen(*wxBLACK,1,wxDOT));
75 dc.SetBrush(*wxTRANSPARENT_BRUSH);
76
77 dc.DrawRectangle(rect);
78
79 dc.SetLogicalFunction(wxCOPY);
80 #endif
81 }
82
83 // -----------------------------------------------------------------------
84 // wxPGCellRenderer
85 // -----------------------------------------------------------------------
86
87 wxSize wxPGCellRenderer::GetImageSize( const wxPGProperty* WXUNUSED(property),
88 int WXUNUSED(column),
89 int WXUNUSED(item) ) const
90 {
91 return wxSize(0, 0);
92 }
93
94 void wxPGCellRenderer::DrawText( wxDC& dc, const wxRect& rect,
95 int xOffset, const wxString& text ) const
96 {
97 if ( xOffset )
98 xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
99 dc.DrawText( text,
100 rect.x+xOffset+wxPG_XBEFORETEXT,
101 rect.y+((rect.height-dc.GetCharHeight())/2) );
102 }
103
104 void wxPGCellRenderer::DrawEditorValue( wxDC& dc, const wxRect& rect,
105 int xOffset, const wxString& text,
106 wxPGProperty* property,
107 const wxPGEditor* editor ) const
108 {
109 if ( xOffset )
110 xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
111
112 int yOffset = ((rect.height-dc.GetCharHeight())/2);
113
114 if ( editor )
115 {
116 wxRect rect2(rect);
117 rect2.x += xOffset;
118 rect2.y += yOffset;
119 rect2.height -= yOffset;
120 editor->DrawValue( dc, rect2, property, text );
121 }
122 else
123 {
124 dc.DrawText( text,
125 rect.x+xOffset+wxPG_XBEFORETEXT,
126 rect.y+yOffset );
127 }
128 }
129
130 void wxPGCellRenderer::DrawCaptionSelectionRect( wxDC& dc, int x, int y, int w, int h ) const
131 {
132 wxRect focusRect(x,y+((h-dc.GetCharHeight())/2),w,h);
133 wxPGDrawFocusRect(dc,focusRect);
134 }
135
136 int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& cell, int flags ) const
137 {
138 int imageOffset = 0;
139
140 // If possible, use cell colours
141 if ( !(flags & DontUseCellBgCol) )
142 {
143 dc.SetPen(cell.GetBgCol());
144 dc.SetBrush(cell.GetBgCol());
145 }
146
147 if ( !(flags & DontUseCellFgCol) )
148 {
149 dc.SetTextForeground(cell.GetFgCol());
150 }
151
152 // Draw Background
153 dc.DrawRectangle(rect);
154
155 const wxBitmap& bmp = cell.GetBitmap();
156 if ( bmp.Ok() &&
157 // Do not draw oversized bitmap outside choice popup
158 ((flags & ChoicePopup) || bmp.GetHeight() < rect.height )
159 )
160 {
161 dc.DrawBitmap( bmp,
162 rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
163 rect.y + wxPG_CUSTOM_IMAGE_SPACINGY,
164 true );
165 imageOffset = bmp.GetWidth();
166 }
167
168 return imageOffset;
169 }
170
171 // -----------------------------------------------------------------------
172 // wxPGDefaultRenderer
173 // -----------------------------------------------------------------------
174
175 void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect,
176 const wxPropertyGrid* propertyGrid, wxPGProperty* property,
177 int column, int item, int flags ) const
178 {
179 bool isUnspecified = property->IsValueUnspecified();
180
181 if ( column == 1 && item == -1 )
182 {
183 int cmnVal = property->GetCommonValue();
184 if ( cmnVal >= 0 )
185 {
186 // Common Value
187 if ( !isUnspecified )
188 DrawText( dc, rect, 0, propertyGrid->GetCommonValueLabel(cmnVal) );
189 return;
190 }
191 }
192
193 const wxPGEditor* editor = NULL;
194 const wxPGCell* cell = NULL;
195
196 wxString text;
197 int imageOffset = 0;
198 int preDrawFlags = flags;
199
200 property->GetDisplayInfo(column, item, flags, &text, &cell);
201
202 imageOffset = PreDrawCell( dc, rect, *cell, preDrawFlags );
203
204 if ( column == 1 )
205 {
206 if ( !isUnspecified )
207 {
208 editor = property->GetColumnEditor(column);
209
210 // Regular property value
211
212 wxSize imageSize = propertyGrid->GetImageSize(property, item);
213
214 wxPGPaintData paintdata;
215 paintdata.m_parent = propertyGrid;
216 paintdata.m_choiceItem = item;
217
218 if ( imageSize.x > 0 )
219 {
220 wxRect imageRect(rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
221 rect.y+wxPG_CUSTOM_IMAGE_SPACINGY,
222 wxPG_CUSTOM_IMAGE_WIDTH,
223 rect.height-(wxPG_CUSTOM_IMAGE_SPACINGY*2));
224
225 dc.SetPen( wxPen(propertyGrid->GetCellTextColour(), 1, wxSOLID) );
226
227 paintdata.m_drawnWidth = imageSize.x;
228 paintdata.m_drawnHeight = imageSize.y;
229
230 property->OnCustomPaint( dc, imageRect, paintdata );
231
232 imageOffset = paintdata.m_drawnWidth;
233 }
234
235 text = property->GetValueAsString();
236
237 // Add units string?
238 if ( propertyGrid->GetColumnCount() <= 2 )
239 {
240 wxString unitsString = property->GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
241 if ( unitsString.length() )
242 text = wxString::Format(wxS("%s %s"), text.c_str(), unitsString.c_str() );
243 }
244 }
245
246 if ( text.length() == 0 )
247 {
248 // Try to show inline help if no text
249 wxVariant vInlineHelp = property->GetAttribute(wxPGGlobalVars->m_strInlineHelp);
250 if ( !vInlineHelp.IsNull() )
251 {
252 text = vInlineHelp.GetString();
253 dc.SetTextForeground(propertyGrid->GetCellDisabledTextColour());
254 }
255 }
256 }
257
258 DrawEditorValue( dc, rect, imageOffset, text, property, editor );
259
260 // active caption gets nice dotted rectangle
261 if ( property->IsCategory() /*&& column == 0*/ )
262 {
263 if ( flags & Selected )
264 {
265 if ( imageOffset > 0 )
266 imageOffset += wxCC_CUSTOM_IMAGE_MARGIN2 + 4;
267
268 DrawCaptionSelectionRect( dc,
269 rect.x+wxPG_XBEFORETEXT-wxPG_CAPRECTXMARGIN+imageOffset,
270 rect.y-wxPG_CAPRECTYMARGIN+1,
271 ((wxPropertyCategory*)property)->GetTextExtent(propertyGrid,
272 propertyGrid->GetCaptionFont())
273 +(wxPG_CAPRECTXMARGIN*2),
274 propertyGrid->GetFontHeight()+(wxPG_CAPRECTYMARGIN*2) );
275 }
276 }
277 }
278
279 wxSize wxPGDefaultRenderer::GetImageSize( const wxPGProperty* property,
280 int column,
281 int item ) const
282 {
283 if ( property && column == 1 )
284 {
285 if ( item == -1 )
286 {
287 wxBitmap* bmp = property->GetValueImage();
288
289 if ( bmp && bmp->Ok() )
290 return wxSize(bmp->GetWidth(),bmp->GetHeight());
291 }
292 }
293 return wxSize(0,0);
294 }
295
296 // -----------------------------------------------------------------------
297 // wxPGCellData
298 // -----------------------------------------------------------------------
299
300 wxPGCellData::wxPGCellData()
301 : wxObjectRefData()
302 {
303 m_hasValidText = false;
304 }
305
306 // -----------------------------------------------------------------------
307 // wxPGCell
308 // -----------------------------------------------------------------------
309
310 wxPGCell::wxPGCell()
311 : wxObject()
312 {
313 }
314
315 wxPGCell::wxPGCell( const wxString& text,
316 const wxBitmap& bitmap,
317 const wxColour& fgCol,
318 const wxColour& bgCol )
319 : wxObject()
320 {
321 wxPGCellData* data = new wxPGCellData();
322 m_refData = data;
323 data->m_text = text;
324 data->m_bitmap = bitmap;
325 data->m_fgCol = fgCol;
326 data->m_bgCol = bgCol;
327 data->m_hasValidText = true;
328 }
329
330 wxObjectRefData *wxPGCell::CloneRefData( const wxObjectRefData *data ) const
331 {
332 wxPGCellData* c = new wxPGCellData();
333 const wxPGCellData* o = (const wxPGCellData*) data;
334 c->m_text = o->m_text;
335 c->m_bitmap = o->m_bitmap;
336 c->m_fgCol = o->m_fgCol;
337 c->m_bgCol = o->m_bgCol;
338 c->m_hasValidText = o->m_hasValidText;
339 return c;
340 }
341
342 void wxPGCell::SetText( const wxString& text )
343 {
344 AllocExclusive();
345
346 GetData()->SetText(text);
347 }
348
349 void wxPGCell::SetBitmap( const wxBitmap& bitmap )
350 {
351 AllocExclusive();
352
353 GetData()->SetBitmap(bitmap);
354 }
355
356 void wxPGCell::SetFgCol( const wxColour& col )
357 {
358 AllocExclusive();
359
360 GetData()->SetFgCol(col);
361 }
362
363 void wxPGCell::SetBgCol( const wxColour& col )
364 {
365 AllocExclusive();
366
367 GetData()->SetBgCol(col);
368 }
369
370 void wxPGCell::MergeFrom( const wxPGCell& srcCell )
371 {
372 AllocExclusive();
373
374 wxPGCellData* data = GetData();
375
376 if ( srcCell.HasText() )
377 data->SetText(srcCell.GetText());
378
379 if ( srcCell.GetFgCol().IsOk() )
380 data->SetFgCol(srcCell.GetFgCol());
381
382 if ( srcCell.GetBgCol().IsOk() )
383 data->SetBgCol(srcCell.GetBgCol());
384
385 if ( srcCell.GetBitmap().IsOk() )
386 data->SetBitmap(srcCell.GetBitmap());
387 }
388
389 // -----------------------------------------------------------------------
390 // wxPGProperty
391 // -----------------------------------------------------------------------
392
393 IMPLEMENT_ABSTRACT_CLASS(wxPGProperty, wxObject)
394
395 wxString* wxPGProperty::sm_wxPG_LABEL = NULL;
396
397 void wxPGProperty::Init()
398 {
399 m_commonValue = -1;
400 m_arrIndex = 0xFFFF;
401 m_parent = NULL;
402
403 m_parentState = (wxPropertyGridPageState*) NULL;
404
405 m_clientData = NULL;
406 m_clientObject = NULL;
407
408 m_customEditor = (wxPGEditor*) NULL;
409 #if wxUSE_VALIDATORS
410 m_validator = (wxValidator*) NULL;
411 #endif
412 m_valueBitmap = (wxBitmap*) NULL;
413
414 m_maxLen = 0; // infinite maximum length
415
416 m_flags = wxPG_PROP_PROPERTY;
417
418 m_depth = 1;
419
420 SetExpanded(true);
421 }
422
423
424 void wxPGProperty::Init( const wxString& label, const wxString& name )
425 {
426 // We really need to check if &label and &name are NULL pointers
427 // (this can if we are called before property grid has been initalized)
428
429 if ( (&label) != NULL && label != wxPG_LABEL )
430 m_label = label;
431
432 if ( (&name) != NULL && name != wxPG_LABEL )
433 DoSetName( name );
434 else
435 DoSetName( m_label );
436
437 Init();
438 }
439
440 void wxPGProperty::InitAfterAdded( wxPropertyGridPageState* pageState,
441 wxPropertyGrid* propgrid )
442 {
443 //
444 // Called after property has been added to grid or page
445 // (so propgrid can be NULL, too).
446
447 wxPGProperty* parent = m_parent;
448 bool parentIsRoot = parent->IsKindOf(CLASSINFO(wxPGRootProperty));
449
450 m_parentState = pageState;
451
452 #if wxPG_COMPATIBILITY_1_4
453 // Make sure deprecated virtual functions are not implemented
454 wxString s = GetValueAsString( 0xFFFF );
455 wxASSERT_MSG( s == g_invalidStringContent,
456 "Implement ValueToString() instead of GetValueAsString()" );
457 #endif
458
459 if ( !parentIsRoot && !parent->IsCategory() )
460 {
461 m_cells = parent->m_cells;
462 }
463
464 // If in hideable adding mode, or if assigned parent is hideable, then
465 // make this one hideable.
466 if (
467 ( !parentIsRoot && parent->HasFlag(wxPG_PROP_HIDDEN) ) ||
468 ( propgrid && (propgrid->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES)) )
469 )
470 SetFlag( wxPG_PROP_HIDDEN );
471
472 // Set custom image flag.
473 int custImgHeight = OnMeasureImage().y;
474 if ( custImgHeight < 0 )
475 {
476 SetFlag(wxPG_PROP_CUSTOMIMAGE);
477 }
478
479 if ( propgrid && (propgrid->HasFlag(wxPG_LIMITED_EDITING)) )
480 SetFlag(wxPG_PROP_NOEDITOR);
481
482 // Make sure parent has some parental flags
483 if ( !parent->HasFlag(wxPG_PROP_PARENTAL_FLAGS) )
484 parent->SetParentalType(wxPG_PROP_MISC_PARENT);
485
486 if ( !IsCategory() )
487 {
488 // This is not a category.
489
490 // Depth.
491 //
492 unsigned char depth = 1;
493 if ( !parentIsRoot )
494 {
495 depth = parent->m_depth;
496 if ( !parent->IsCategory() )
497 depth++;
498 }
499 m_depth = depth;
500 unsigned char greyDepth = depth;
501
502 if ( !parentIsRoot )
503 {
504 wxPropertyCategory* pc;
505
506 if ( parent->IsCategory() )
507 pc = (wxPropertyCategory* ) parent;
508 else
509 // This conditional compile is necessary to
510 // bypass some compiler bug.
511 pc = pageState->GetPropertyCategory(parent);
512
513 if ( pc )
514 greyDepth = pc->GetDepth();
515 else
516 greyDepth = parent->m_depthBgCol;
517 }
518
519 m_depthBgCol = greyDepth;
520 }
521 else
522 {
523 // This is a category.
524
525 // depth
526 unsigned char depth = 1;
527 if ( !parentIsRoot )
528 {
529 depth = parent->m_depth + 1;
530 }
531 m_depth = depth;
532 m_depthBgCol = depth;
533 }
534
535 //
536 // Has initial children
537 if ( GetChildCount() )
538 {
539 // Check parental flags
540 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS),
541 "Call SetFlag(wxPG_PROP_MISC_PARENT) or"
542 "SetFlag(wxPG_PROP_AGGREGATE) before calling"
543 "wxPGProperty::AddChild()." );
544
545 if ( HasFlag(wxPG_PROP_AGGREGATE) )
546 {
547 // Properties with private children are not expanded by default.
548 SetExpanded(false);
549 }
550 else if ( propgrid && propgrid->HasFlag(wxPG_HIDE_MARGIN) )
551 {
552 // ...unless it cannot be expanded by user and therefore must
553 // remain visible at all times
554 SetExpanded(true);
555 }
556
557 //
558 // Prepare children recursively
559 for ( unsigned int i=0; i<GetChildCount(); i++ )
560 {
561 wxPGProperty* child = Item(i);
562 child->InitAfterAdded(pageState, pageState->GetGrid());
563 }
564
565 if ( propgrid && (propgrid->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES) )
566 SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED, true);
567 }
568 }
569
570 wxPGProperty::wxPGProperty()
571 : wxObject()
572 {
573 Init();
574 }
575
576
577 wxPGProperty::wxPGProperty( const wxString& label, const wxString& name )
578 : wxObject()
579 {
580 Init( label, name );
581 }
582
583
584 wxPGProperty::~wxPGProperty()
585 {
586 delete m_clientObject;
587
588 Empty(); // this deletes items
589
590 delete m_valueBitmap;
591 #if wxUSE_VALIDATORS
592 delete m_validator;
593 #endif
594
595 // This makes it easier for us to detect dangling pointers
596 m_parent = NULL;
597 }
598
599
600 bool wxPGProperty::IsSomeParent( wxPGProperty* candidate ) const
601 {
602 wxPGProperty* parent = m_parent;
603 do
604 {
605 if ( parent == candidate )
606 return true;
607 parent = parent->m_parent;
608 } while ( parent );
609 return false;
610 }
611
612
613 wxString wxPGProperty::GetName() const
614 {
615 wxPGProperty* parent = GetParent();
616
617 if ( !m_name.length() || !parent || parent->IsCategory() || parent->IsRoot() )
618 return m_name;
619
620 return m_parent->GetName() + wxS(".") + m_name;
621 }
622
623 wxPropertyGrid* wxPGProperty::GetGrid() const
624 {
625 if ( !m_parentState )
626 return NULL;
627 return m_parentState->GetGrid();
628 }
629
630 int wxPGProperty::Index( const wxPGProperty* p ) const
631 {
632 for ( unsigned int i = 0; i<m_children.size(); i++ )
633 {
634 if ( p == m_children[i] )
635 return i;
636 }
637 return wxNOT_FOUND;
638 }
639
640 void wxPGProperty::UpdateControl( wxWindow* primary )
641 {
642 if ( primary )
643 GetEditorClass()->UpdateControl(this, primary);
644 }
645
646 bool wxPGProperty::ValidateValue( wxVariant& WXUNUSED(value), wxPGValidationInfo& WXUNUSED(validationInfo) ) const
647 {
648 return true;
649 }
650
651 void wxPGProperty::OnSetValue()
652 {
653 }
654
655 void wxPGProperty::RefreshChildren ()
656 {
657 }
658
659 void wxPGProperty::GetDisplayInfo( unsigned int column,
660 int choiceIndex,
661 int flags,
662 wxString* pString,
663 const wxPGCell** pCell )
664 {
665 const wxPGCell* cell = NULL;
666
667 if ( !(flags & wxPGCellRenderer::ChoicePopup) )
668 {
669 // Not painting listi of choice popups, so get text from property
670 cell = &GetCell(column);
671 if ( cell->HasText() )
672 {
673 *pString = cell->GetText();
674 }
675 else
676 {
677 if ( column == 0 )
678 *pString = GetLabel();
679 else if ( column == 1 )
680 *pString = GetDisplayedString();
681 else if ( column == 2 )
682 *pString = GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
683 }
684 }
685 else
686 {
687 wxASSERT( column == 1 );
688
689 if ( choiceIndex != wxNOT_FOUND )
690 {
691 const wxPGChoiceEntry& entry = m_choices[choiceIndex];
692 if ( entry.GetBitmap().IsOk() ||
693 entry.GetFgCol().IsOk() ||
694 entry.GetBgCol().IsOk() )
695 cell = &entry;
696 *pString = m_choices.GetLabel(choiceIndex);
697 }
698 }
699
700 if ( !cell )
701 cell = &GetCell(column);
702
703 wxASSERT_MSG( cell->GetData(),
704 wxString::Format("Invalid cell for property %s",
705 GetName().c_str()) );
706
707 *pCell = cell;
708 }
709
710 /*
711 wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
712 {
713
714 if ( col != 1 || choiceIndex == wxNOT_FOUND )
715 {
716 const wxPGCell& cell = GetCell(col);
717 if ( cell->HasText() )
718 {
719 return cell->GetText();
720 }
721 else
722 {
723 if ( col == 0 )
724 return GetLabel();
725 else if ( col == 1 )
726 return GetDisplayedString();
727 else if ( col == 2 )
728 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
729 }
730 }
731 else
732 {
733 // Use choice
734 return m_choices.GetLabel(choiceIndex);
735 }
736
737 return wxEmptyString;
738 }
739 */
740
741 void wxPGProperty::DoGenerateComposedValue( wxString& text,
742 int argFlags,
743 const wxVariantList* valueOverrides,
744 wxPGHashMapS2S* childResults ) const
745 {
746 int i;
747 int iMax = m_children.size();
748
749 text.clear();
750 if ( iMax == 0 )
751 return;
752
753 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
754 !(argFlags & wxPG_FULL_VALUE) )
755 iMax = PWC_CHILD_SUMMARY_LIMIT;
756
757 int iMaxMinusOne = iMax-1;
758
759 if ( !IsTextEditable() )
760 argFlags |= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT;
761
762 wxPGProperty* curChild = m_children[0];
763
764 bool overridesLeft = false;
765 wxVariant overrideValue;
766 wxVariantList::const_iterator node;
767
768 if ( valueOverrides )
769 {
770 node = valueOverrides->begin();
771 if ( node != valueOverrides->end() )
772 {
773 overrideValue = *node;
774 overridesLeft = true;
775 }
776 }
777
778 for ( i = 0; i < iMax; i++ )
779 {
780 wxVariant childValue;
781
782 wxString childLabel = curChild->GetLabel();
783
784 // Check for value override
785 if ( overridesLeft && overrideValue.GetName() == childLabel )
786 {
787 if ( !overrideValue.IsNull() )
788 childValue = overrideValue;
789 else
790 childValue = curChild->GetValue();
791 ++node;
792 if ( node != valueOverrides->end() )
793 overrideValue = *node;
794 else
795 overridesLeft = false;
796 }
797 else
798 {
799 childValue = curChild->GetValue();
800 }
801
802 wxString s;
803 if ( !childValue.IsNull() )
804 {
805 if ( overridesLeft &&
806 curChild->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
807 childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
808 {
809 wxVariantList& childList = childValue.GetList();
810 DoGenerateComposedValue(s, argFlags|wxPG_COMPOSITE_FRAGMENT,
811 &childList, childResults);
812 }
813 else
814 {
815 s = curChild->ValueToString(childValue,
816 argFlags|wxPG_COMPOSITE_FRAGMENT);
817 }
818 }
819
820 if ( childResults && curChild->GetChildCount() )
821 (*childResults)[curChild->GetName()] = s;
822
823 bool skip = false;
824 if ( (argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT) && !s.length() )
825 skip = true;
826
827 if ( !curChild->GetChildCount() || skip )
828 text += s;
829 else
830 text += wxS("[") + s + wxS("]");
831
832 if ( i < iMaxMinusOne )
833 {
834 if ( text.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT &&
835 !(argFlags & wxPG_EDITABLE_VALUE) &&
836 !(argFlags & wxPG_FULL_VALUE) )
837 break;
838
839 if ( !skip )
840 {
841 if ( !curChild->GetChildCount() )
842 text += wxS("; ");
843 else
844 text += wxS(" ");
845 }
846
847 curChild = m_children[i+1];
848 }
849 }
850
851 if ( (unsigned int)i < m_children.size() )
852 {
853 if ( !text.EndsWith(wxS("; ")) )
854 text += wxS("; ...");
855 else
856 text += wxS("...");
857 }
858 }
859
860 wxString wxPGProperty::ValueToString( wxVariant& WXUNUSED(value),
861 int argFlags ) const
862 {
863 wxCHECK_MSG( GetChildCount() > 0,
864 wxString(),
865 "If user property does not have any children, it must "
866 "override GetValueAsString" );
867
868 // FIXME: Currently code below only works if value is actually m_value
869 wxASSERT_MSG( argFlags & wxPG_VALUE_IS_CURRENT,
870 "Sorry, currently default wxPGProperty::ValueToString() "
871 "implementation only works if value is m_value." );
872
873 wxString text;
874 DoGenerateComposedValue(text, argFlags);
875 return text;
876 }
877
878 wxString wxPGProperty::GetValueAsString( int argFlags ) const
879 {
880 #if wxPG_COMPATIBILITY_1_4
881 // This is backwards compatibility test
882 // That is, to make sure this function is not overridden
883 // (instead, ValueToString() should be).
884 if ( argFlags == 0xFFFF )
885 {
886 // Do not override! (for backwards compliancy)
887 return g_invalidStringContent;
888 }
889 #endif
890
891 if ( IsValueUnspecified() )
892 return wxEmptyString;
893
894 if ( m_commonValue == -1 )
895 {
896 wxVariant value(GetValue());
897 return ValueToString(value, argFlags|wxPG_VALUE_IS_CURRENT);
898 }
899
900 //
901 // Return common value's string representation
902 wxPropertyGrid* pg = GetGrid();
903 const wxPGCommonValue* cv = pg->GetCommonValue(m_commonValue);
904
905 if ( argFlags & wxPG_FULL_VALUE )
906 {
907 return cv->GetLabel();
908 }
909 else if ( argFlags & wxPG_EDITABLE_VALUE )
910 {
911 return cv->GetEditableText();
912 }
913 else
914 {
915 return cv->GetLabel();
916 }
917 }
918
919 wxString wxPGProperty::GetValueString( int argFlags ) const
920 {
921 return GetValueAsString(argFlags);
922 }
923
924 bool wxPGProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const
925 {
926 variant = (long)number;
927 return true;
928 }
929
930 // Convert semicolon delimited tokens into child values.
931 bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
932 {
933 if ( !GetChildCount() )
934 return false;
935
936 unsigned int curChild = 0;
937
938 unsigned int iMax = m_children.size();
939
940 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
941 !(argFlags & wxPG_FULL_VALUE) )
942 iMax = PWC_CHILD_SUMMARY_LIMIT;
943
944 bool changed = false;
945
946 wxString token;
947 size_t pos = 0;
948
949 // Its best only to add non-empty group items
950 bool addOnlyIfNotEmpty = false;
951 const wxChar delimeter = wxS(';');
952
953 size_t tokenStart = 0xFFFFFF;
954
955 wxVariantList temp_list;
956 wxVariant list(temp_list);
957
958 int propagatedFlags = argFlags & (wxPG_REPORT_ERROR|wxPG_PROGRAMMATIC_VALUE);
959
960 #ifdef __WXDEBUG__
961 bool debug_print = false;
962 #endif
963
964 #ifdef __WXDEBUG__
965 if ( debug_print )
966 wxLogDebug(wxT(">> %s.StringToValue('%s')"),GetLabel().c_str(),text.c_str());
967 #endif
968
969 wxString::const_iterator it = text.begin();
970 wxUniChar a;
971
972 if ( it != text.end() )
973 a = *it;
974 else
975 a = 0;
976
977 for ( ;; )
978 {
979 if ( tokenStart != 0xFFFFFF )
980 {
981 // Token is running
982 if ( a == delimeter || a == 0 )
983 {
984 token = text.substr(tokenStart,pos-tokenStart);
985 token.Trim(true);
986 size_t len = token.length();
987
988 if ( !addOnlyIfNotEmpty || len > 0 )
989 {
990 const wxPGProperty* child = Item(curChild);
991 wxVariant variant(child->GetValue());
992 variant.SetName(child->GetBaseName());
993
994 #ifdef __WXDEBUG__
995 if ( debug_print )
996 wxLogDebug(wxT("token = '%s', child = %s"),token.c_str(),child->GetLabel().c_str());
997 #endif
998
999 // Add only if editable or setting programmatically
1000 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
1001 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1002 {
1003 if ( len > 0 )
1004 {
1005 if ( child->StringToValue(variant, token, propagatedFlags|wxPG_COMPOSITE_FRAGMENT) )
1006 {
1007 list.Append(variant);
1008
1009 changed = true;
1010 }
1011 }
1012 else
1013 {
1014 // Empty, becomes unspecified
1015 variant.MakeNull();
1016 list.Append(variant);
1017 changed = true;
1018 }
1019 }
1020
1021 curChild++;
1022 if ( curChild >= iMax )
1023 break;
1024 }
1025
1026 tokenStart = 0xFFFFFF;
1027 }
1028 }
1029 else
1030 {
1031 // Token is not running
1032 if ( a != wxS(' ') )
1033 {
1034
1035 addOnlyIfNotEmpty = false;
1036
1037 // Is this a group of tokens?
1038 if ( a == wxS('[') )
1039 {
1040 int depth = 1;
1041
1042 if ( it != text.end() ) ++it;
1043 pos++;
1044 size_t startPos = pos;
1045
1046 // Group item - find end
1047 while ( it != text.end() && depth > 0 )
1048 {
1049 a = *it;
1050 ++it;
1051 pos++;
1052
1053 if ( a == wxS(']') )
1054 depth--;
1055 else if ( a == wxS('[') )
1056 depth++;
1057 }
1058
1059 token = text.substr(startPos,pos-startPos-1);
1060
1061 if ( !token.length() )
1062 break;
1063
1064 const wxPGProperty* child = Item(curChild);
1065
1066 wxVariant oldChildValue = child->GetValue();
1067 wxVariant variant(oldChildValue);
1068
1069 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
1070 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1071 {
1072 bool stvRes = child->StringToValue( variant, token, propagatedFlags );
1073 if ( stvRes || (variant != oldChildValue) )
1074 {
1075 if ( stvRes )
1076 changed = true;
1077 }
1078 else
1079 {
1080 // Failed, becomes unspecified
1081 variant.MakeNull();
1082 changed = true;
1083 }
1084 }
1085
1086 variant.SetName(child->GetBaseName());
1087 list.Append(variant);
1088
1089 curChild++;
1090 if ( curChild >= iMax )
1091 break;
1092
1093 addOnlyIfNotEmpty = true;
1094
1095 tokenStart = 0xFFFFFF;
1096 }
1097 else
1098 {
1099 tokenStart = pos;
1100
1101 if ( a == delimeter )
1102 {
1103 pos--;
1104 --it;
1105 }
1106 }
1107 }
1108 }
1109
1110 if ( a == 0 )
1111 break;
1112
1113 ++it;
1114 if ( it != text.end() )
1115 {
1116 a = *it;
1117 }
1118 else
1119 {
1120 a = 0;
1121 }
1122 pos++;
1123 }
1124
1125 if ( changed )
1126 variant = list;
1127
1128 return changed;
1129 }
1130
1131 bool wxPGProperty::SetValueFromString( const wxString& text, int argFlags )
1132 {
1133 wxVariant variant(m_value);
1134 bool res = StringToValue(variant, text, argFlags);
1135 if ( res )
1136 SetValue(variant);
1137 return res;
1138 }
1139
1140 bool wxPGProperty::SetValueFromInt( long number, int argFlags )
1141 {
1142 wxVariant variant(m_value);
1143 bool res = IntToValue(variant, number, argFlags);
1144 if ( res )
1145 SetValue(variant);
1146 return res;
1147 }
1148
1149 wxSize wxPGProperty::OnMeasureImage( int WXUNUSED(item) ) const
1150 {
1151 if ( m_valueBitmap )
1152 return wxSize(m_valueBitmap->GetWidth(),-1);
1153
1154 return wxSize(0,0);
1155 }
1156
1157 wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const
1158 {
1159 return wxPGGlobalVars->m_defaultRenderer;
1160 }
1161
1162 void wxPGProperty::OnCustomPaint( wxDC& dc,
1163 const wxRect& rect,
1164 wxPGPaintData& )
1165 {
1166 wxBitmap* bmp = m_valueBitmap;
1167
1168 wxCHECK_RET( bmp && bmp->Ok(), wxT("invalid bitmap") );
1169
1170 wxCHECK_RET( rect.x >= 0, wxT("unexpected measure call") );
1171
1172 dc.DrawBitmap(*bmp,rect.x,rect.y);
1173 }
1174
1175 const wxPGEditor* wxPGProperty::DoGetEditorClass() const
1176 {
1177 return wxPGEditor_TextCtrl;
1178 }
1179
1180 // Default extra property event handling - that is, none at all.
1181 bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& )
1182 {
1183 return false;
1184 }
1185
1186
1187 void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags )
1188 {
1189 // If auto unspecified values are not wanted (via window or property style),
1190 // then get default value instead of wxNullVariant.
1191 if ( value.IsNull() && (flags & wxPG_SETVAL_BY_USER) &&
1192 !UsesAutoUnspecified() )
1193 {
1194 value = GetDefaultValue();
1195 }
1196
1197 if ( !value.IsNull() )
1198 {
1199 wxVariant tempListVariant;
1200
1201 SetCommonValue(-1);
1202 // List variants are reserved a special purpose
1203 // as intermediate containers for child values
1204 // of properties with children.
1205 if ( value.GetType() == wxPG_VARIANT_TYPE_LIST )
1206 {
1207 //
1208 // However, situation is different for composed string properties
1209 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
1210 {
1211 tempListVariant = value;
1212 pList = &tempListVariant;
1213 }
1214
1215 wxVariant newValue;
1216 AdaptListToValue(value, &newValue);
1217 value = newValue;
1218 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1219 }
1220
1221 if ( HasFlag( wxPG_PROP_AGGREGATE) )
1222 flags |= wxPG_SETVAL_AGGREGATED;
1223
1224 if ( pList && !pList->IsNull() )
1225 {
1226 wxASSERT( pList->GetType() == wxPG_VARIANT_TYPE_LIST );
1227 wxASSERT( GetChildCount() );
1228 wxASSERT( !IsCategory() );
1229
1230 wxVariantList& list = pList->GetList();
1231 wxVariantList::iterator node;
1232 unsigned int i = 0;
1233
1234 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1235
1236 // Children in list can be in any order, but we will give hint to
1237 // GetPropertyByNameWH(). This optimizes for full list parsing.
1238 for ( node = list.begin(); node != list.end(); ++node )
1239 {
1240 wxVariant& childValue = *((wxVariant*)*node);
1241 wxPGProperty* child = GetPropertyByNameWH(childValue.GetName(), i);
1242 if ( child )
1243 {
1244 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
1245 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1246 {
1247 if ( child->HasFlag(wxPG_PROP_AGGREGATE) && !(flags & wxPG_SETVAL_AGGREGATED) )
1248 {
1249 wxVariant listRefCopy = childValue;
1250 child->SetValue(childValue, &listRefCopy, flags|wxPG_SETVAL_FROM_PARENT);
1251 }
1252 else
1253 {
1254 wxVariant oldVal = child->GetValue();
1255 child->SetValue(oldVal, &childValue, flags|wxPG_SETVAL_FROM_PARENT);
1256 }
1257 }
1258 else if ( child->GetValue() != childValue )
1259 {
1260 // For aggregate properties, we will trust RefreshChildren()
1261 // to update child values.
1262 if ( !HasFlag(wxPG_PROP_AGGREGATE) )
1263 child->SetValue(childValue, NULL, flags|wxPG_SETVAL_FROM_PARENT);
1264 if ( flags & wxPG_SETVAL_BY_USER )
1265 child->SetFlag(wxPG_PROP_MODIFIED);
1266 }
1267 }
1268 i++;
1269 }
1270 }
1271
1272 if ( !value.IsNull() )
1273 {
1274 m_value = value;
1275 OnSetValue();
1276
1277 if ( !(flags & wxPG_SETVAL_FROM_PARENT) )
1278 UpdateParentValues();
1279 }
1280
1281 if ( flags & wxPG_SETVAL_BY_USER )
1282 SetFlag(wxPG_PROP_MODIFIED);
1283
1284 if ( HasFlag(wxPG_PROP_AGGREGATE) )
1285 RefreshChildren();
1286 }
1287 else
1288 {
1289 if ( m_commonValue != -1 )
1290 {
1291 wxPropertyGrid* pg = GetGrid();
1292 if ( !pg || m_commonValue != pg->GetUnspecifiedCommonValue() )
1293 SetCommonValue(-1);
1294 }
1295
1296 m_value = value;
1297
1298 // Set children to unspecified, but only if aggregate or
1299 // value is <composed>
1300 if ( AreChildrenComponents() )
1301 {
1302 unsigned int i;
1303 for ( i=0; i<GetChildCount(); i++ )
1304 Item(i)->SetValue(value, NULL, flags|wxPG_SETVAL_FROM_PARENT);
1305 }
1306 }
1307
1308 //
1309 // Update editor control
1310 //
1311
1312 // We need to check for these, otherwise GetGrid() may fail.
1313 if ( flags & wxPG_SETVAL_REFRESH_EDITOR )
1314 RefreshEditor();
1315 }
1316
1317
1318 void wxPGProperty::SetValueInEvent( wxVariant value ) const
1319 {
1320 GetGrid()->ValueChangeInEvent(value);
1321 }
1322
1323 void wxPGProperty::SetFlagRecursively( FlagType flag, bool set )
1324 {
1325 if ( set )
1326 SetFlag(flag);
1327 else
1328 ClearFlag(flag);
1329
1330 unsigned int i;
1331 for ( i = 0; i < GetChildCount(); i++ )
1332 Item(i)->SetFlagRecursively(flag, set);
1333 }
1334
1335 void wxPGProperty::RefreshEditor()
1336 {
1337 if ( m_parent && GetParentState() )
1338 {
1339 wxPropertyGrid* pg = GetParentState()->GetGrid();
1340 if ( pg->GetSelectedProperty() == this )
1341 {
1342 wxWindow* editor = pg->GetEditorControl();
1343 if ( editor )
1344 GetEditorClass()->UpdateControl( this, editor );
1345 }
1346 }
1347 }
1348
1349
1350 wxVariant wxPGProperty::GetDefaultValue() const
1351 {
1352 wxVariant defVal = GetAttribute(wxS("DefaultValue"));
1353 if ( !defVal.IsNull() )
1354 return defVal;
1355
1356 wxVariant value = GetValue();
1357
1358 if ( !value.IsNull() )
1359 {
1360 wxString valueType(value.GetType());
1361
1362 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1363 return wxPGVariant_Zero;
1364 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1365 return wxPGVariant_EmptyString;
1366 if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1367 return wxPGVariant_False;
1368 if ( valueType == wxPG_VARIANT_TYPE_DOUBLE )
1369 return wxVariant(0.0);
1370 if ( valueType == wxPG_VARIANT_TYPE_ARRSTRING )
1371 return wxVariant(wxArrayString());
1372 if ( valueType == wxS("wxLongLong") )
1373 return WXVARIANT(wxLongLong(0));
1374 if ( valueType == wxS("wxULongLong") )
1375 return WXVARIANT(wxULongLong(0));
1376 if ( valueType == wxS("wxColour") )
1377 return WXVARIANT(*wxBLACK);
1378 #if wxUSE_DATETIME
1379 if ( valueType == wxPG_VARIANT_TYPE_DATETIME )
1380 return wxVariant(wxDateTime::Now());
1381 #endif
1382 if ( valueType == wxS("wxFont") )
1383 return WXVARIANT(*wxNORMAL_FONT);
1384 if ( valueType == wxS("wxPoint") )
1385 return WXVARIANT(wxPoint(0, 0));
1386 if ( valueType == wxS("wxSize") )
1387 return WXVARIANT(wxSize(0, 0));
1388 }
1389
1390 return wxVariant();
1391 }
1392
1393 void wxPGProperty::EnsureCells( unsigned int column )
1394 {
1395 if ( column >= m_cells.size() )
1396 {
1397 // Fill empty slots with default cells
1398 wxPropertyGrid* pg = GetGrid();
1399 wxPGCell defaultCell;
1400
1401 if ( !HasFlag(wxPG_PROP_CATEGORY) )
1402 defaultCell = pg->GetPropertyDefaultCell();
1403 else
1404 defaultCell = pg->GetCategoryDefaultCell();
1405
1406 // TODO: Replace with resize() call
1407 unsigned int cellCountMax = column+1;
1408
1409 for ( unsigned int i=m_cells.size(); i<cellCountMax; i++ )
1410 m_cells.push_back(defaultCell);
1411 }
1412 }
1413
1414 void wxPGProperty::SetCell( int column,
1415 const wxPGCell& cell )
1416 {
1417 EnsureCells(column);
1418
1419 m_cells[column] = cell;
1420 }
1421
1422 void wxPGProperty::AdaptiveSetCell( unsigned int firstCol,
1423 unsigned int lastCol,
1424 const wxPGCell& cell,
1425 const wxPGCell& srcData,
1426 wxPGCellData* unmodCellData,
1427 FlagType ignoreWithFlags,
1428 bool recursively )
1429 {
1430 //
1431 // Sets cell in memory optimizing fashion. That is, if
1432 // current cell data matches unmodCellData, we will
1433 // simply get reference to data from cell. Otherwise,
1434 // cell information from srcData is merged into current.
1435 //
1436
1437 if ( !(m_flags & ignoreWithFlags) && !IsRoot() )
1438 {
1439 EnsureCells(lastCol);
1440
1441 for ( unsigned int col=firstCol; col<=lastCol; col++ )
1442 {
1443 if ( m_cells[col].GetData() == unmodCellData )
1444 {
1445 // Data matches... use cell directly
1446 m_cells[col] = cell;
1447 }
1448 else
1449 {
1450 // Data did not match... merge valid information
1451 m_cells[col].MergeFrom(srcData);
1452 }
1453 }
1454 }
1455
1456 if ( recursively )
1457 {
1458 for ( unsigned int i=0; i<GetChildCount(); i++ )
1459 Item(i)->AdaptiveSetCell( firstCol,
1460 lastCol,
1461 cell,
1462 srcData,
1463 unmodCellData,
1464 ignoreWithFlags,
1465 recursively );
1466 }
1467 }
1468
1469 const wxPGCell& wxPGProperty::GetCell( unsigned int column ) const
1470 {
1471 if ( m_cells.size() > column )
1472 return m_cells[column];
1473
1474 wxPropertyGrid* pg = GetGrid();
1475
1476 if ( IsCategory() )
1477 return pg->GetCategoryDefaultCell();
1478
1479 return pg->GetPropertyDefaultCell();
1480 }
1481
1482 wxPGCell& wxPGProperty::GetCell( unsigned int column )
1483 {
1484 EnsureCells(column);
1485 return m_cells[column];
1486 }
1487
1488 void wxPGProperty::SetBackgroundColour( const wxColour& colour,
1489 bool recursively )
1490 {
1491 wxPGProperty* firstProp = this;
1492
1493 //
1494 // If category is tried to set recursively, skip it and only
1495 // affect the children.
1496 if ( recursively )
1497 {
1498 while ( firstProp->IsCategory() )
1499 {
1500 if ( !firstProp->GetChildCount() )
1501 return;
1502 firstProp = firstProp->Item(0);
1503 }
1504 }
1505
1506 wxPGCell& firstCell = firstProp->GetCell(0);
1507 wxPGCellData* firstCellData = firstCell.GetData();
1508
1509 wxPGCell newCell(firstCell);
1510 newCell.SetBgCol(colour);
1511 wxPGCell srcCell;
1512 srcCell.SetBgCol(colour);
1513
1514 AdaptiveSetCell( 0,
1515 GetParentState()->GetColumnCount()-1,
1516 newCell,
1517 srcCell,
1518 firstCellData,
1519 recursively ? wxPG_PROP_CATEGORY : 0,
1520 recursively );
1521 }
1522
1523 void wxPGProperty::SetTextColour( const wxColour& colour,
1524 bool recursively )
1525 {
1526 wxPGProperty* firstProp = this;
1527
1528 //
1529 // If category is tried to set recursively, skip it and only
1530 // affect the children.
1531 if ( recursively )
1532 {
1533 while ( firstProp->IsCategory() )
1534 {
1535 if ( !firstProp->GetChildCount() )
1536 return;
1537 firstProp = firstProp->Item(0);
1538 }
1539 }
1540
1541 wxPGCell& firstCell = firstProp->GetCell(0);
1542 wxPGCellData* firstCellData = firstCell.GetData();
1543
1544 wxPGCell newCell(firstCell);
1545 newCell.SetFgCol(colour);
1546 wxPGCell srcCell;
1547 srcCell.SetFgCol(colour);
1548
1549 AdaptiveSetCell( 0,
1550 GetParentState()->GetColumnCount()-1,
1551 newCell,
1552 srcCell,
1553 firstCellData,
1554 recursively ? wxPG_PROP_CATEGORY : 0,
1555 recursively );
1556 }
1557
1558 wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const
1559 {
1560 return NULL;
1561 }
1562
1563 bool wxPGProperty::DoSetAttribute( const wxString& WXUNUSED(name), wxVariant& WXUNUSED(value) )
1564 {
1565 return false;
1566 }
1567
1568 void wxPGProperty::SetAttribute( const wxString& name, wxVariant value )
1569 {
1570 if ( DoSetAttribute( name, value ) )
1571 {
1572 // Support working without grid, when possible
1573 if ( wxPGGlobalVars->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES ) )
1574 return;
1575 }
1576
1577 m_attributes.Set( name, value );
1578 }
1579
1580 void wxPGProperty::SetAttributes( const wxPGAttributeStorage& attributes )
1581 {
1582 wxPGAttributeStorage::const_iterator it = attributes.StartIteration();
1583 wxVariant variant;
1584
1585 while ( attributes.GetNext(it, variant) )
1586 SetAttribute( variant.GetName(), variant );
1587 }
1588
1589 wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
1590 {
1591 return wxVariant();
1592 }
1593
1594
1595 wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
1596 {
1597 return m_attributes.FindValue(name);
1598 }
1599
1600 wxString wxPGProperty::GetAttribute( const wxString& name, const wxString& defVal ) const
1601 {
1602 wxVariant variant = m_attributes.FindValue(name);
1603
1604 if ( !variant.IsNull() )
1605 return variant.GetString();
1606
1607 return defVal;
1608 }
1609
1610 long wxPGProperty::GetAttributeAsLong( const wxString& name, long defVal ) const
1611 {
1612 wxVariant variant = m_attributes.FindValue(name);
1613
1614 return wxPGVariantToInt(variant, defVal);
1615 }
1616
1617 double wxPGProperty::GetAttributeAsDouble( const wxString& name, double defVal ) const
1618 {
1619 double retVal;
1620 wxVariant variant = m_attributes.FindValue(name);
1621
1622 if ( wxPGVariantToDouble(variant, &retVal) )
1623 return retVal;
1624
1625 return defVal;
1626 }
1627
1628 wxVariant wxPGProperty::GetAttributesAsList() const
1629 {
1630 wxVariantList tempList;
1631 wxVariant v( tempList, wxString::Format(wxS("@%s@attr"),m_name.c_str()) );
1632
1633 wxPGAttributeStorage::const_iterator it = m_attributes.StartIteration();
1634 wxVariant variant;
1635
1636 while ( m_attributes.GetNext(it, variant) )
1637 v.Append(variant);
1638
1639 return v;
1640 }
1641
1642 // Slots of utility flags are NULL
1643 const unsigned int gs_propFlagToStringSize = 14;
1644
1645 static const wxChar* gs_propFlagToString[gs_propFlagToStringSize] = {
1646 NULL,
1647 wxT("DISABLED"),
1648 wxT("HIDDEN"),
1649 NULL,
1650 wxT("NOEDITOR"),
1651 wxT("COLLAPSED"),
1652 NULL,
1653 NULL,
1654 NULL,
1655 NULL,
1656 NULL,
1657 NULL,
1658 NULL,
1659 NULL
1660 };
1661
1662 wxString wxPGProperty::GetFlagsAsString( FlagType flagsMask ) const
1663 {
1664 wxString s;
1665 int relevantFlags = m_flags & flagsMask & wxPG_STRING_STORED_FLAGS;
1666 FlagType a = 1;
1667
1668 unsigned int i = 0;
1669 for ( i=0; i<gs_propFlagToStringSize; i++ )
1670 {
1671 if ( relevantFlags & a )
1672 {
1673 const wxChar* fs = gs_propFlagToString[i];
1674 wxASSERT(fs);
1675 if ( s.length() )
1676 s << wxS("|");
1677 s << fs;
1678 }
1679 a = a << 1;
1680 }
1681
1682 return s;
1683 }
1684
1685 void wxPGProperty::SetFlagsFromString( const wxString& str )
1686 {
1687 FlagType flags = 0;
1688
1689 WX_PG_TOKENIZER1_BEGIN(str, wxS('|'))
1690 unsigned int i;
1691 for ( i=0; i<gs_propFlagToStringSize; i++ )
1692 {
1693 const wxChar* fs = gs_propFlagToString[i];
1694 if ( fs && str == fs )
1695 {
1696 flags |= (1<<i);
1697 break;
1698 }
1699 }
1700 WX_PG_TOKENIZER1_END()
1701
1702 m_flags = (m_flags & ~wxPG_STRING_STORED_FLAGS) | flags;
1703 }
1704
1705 wxValidator* wxPGProperty::DoGetValidator() const
1706 {
1707 return (wxValidator*) NULL;
1708 }
1709
1710 int wxPGProperty::InsertChoice( const wxString& label, int index, int value )
1711 {
1712 wxPropertyGrid* pg = GetGrid();
1713 int sel = GetChoiceSelection();
1714
1715 int newSel = sel;
1716
1717 if ( index == wxNOT_FOUND )
1718 index = m_choices.GetCount();
1719
1720 if ( index <= sel )
1721 newSel++;
1722
1723 m_choices.Insert(label, index, value);
1724
1725 if ( sel != newSel )
1726 SetChoiceSelection(newSel);
1727
1728 if ( this == pg->GetSelection() )
1729 GetEditorClass()->InsertItem(pg->GetEditorControl(),label,index);
1730
1731 return index;
1732 }
1733
1734
1735 void wxPGProperty::DeleteChoice( int index )
1736 {
1737 wxPropertyGrid* pg = GetGrid();
1738
1739 int sel = GetChoiceSelection();
1740 int newSel = sel;
1741
1742 // Adjust current value
1743 if ( sel == index )
1744 {
1745 SetValueToUnspecified();
1746 newSel = 0;
1747 }
1748 else if ( index < sel )
1749 {
1750 newSel--;
1751 }
1752
1753 m_choices.RemoveAt(index);
1754
1755 if ( sel != newSel )
1756 SetChoiceSelection(newSel);
1757
1758 if ( this == pg->GetSelection() )
1759 GetEditorClass()->DeleteItem(pg->GetEditorControl(), index);
1760 }
1761
1762 int wxPGProperty::GetChoiceSelection() const
1763 {
1764 wxVariant value = GetValue();
1765 wxString valueType = value.GetType();
1766 int index = wxNOT_FOUND;
1767
1768 if ( IsValueUnspecified() || !m_choices.GetCount() )
1769 return wxNOT_FOUND;
1770
1771 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1772 {
1773 index = value.GetLong();
1774 }
1775 else if ( valueType == wxPG_VARIANT_TYPE_STRING )
1776 {
1777 index = m_choices.Index(value.GetString());
1778 }
1779 else if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1780 {
1781 index = value.GetBool()? 1 : 0;
1782 }
1783
1784 return index;
1785 }
1786
1787 void wxPGProperty::SetChoiceSelection( int newValue )
1788 {
1789 // Changes value of a property with choices, but only
1790 // works if the value type is long or string.
1791 wxString valueType = GetValue().GetType();
1792
1793 wxCHECK_RET( m_choices.IsOk(), wxT("invalid choiceinfo") );
1794
1795 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1796 {
1797 SetValue( m_choices.GetLabel(newValue) );
1798 }
1799 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1800 {
1801 SetValue( (long) newValue );
1802 }
1803 }
1804
1805 bool wxPGProperty::SetChoices( wxPGChoices& choices )
1806 {
1807 m_choices.Assign(choices);
1808
1809 {
1810 // This may be needed to trigger some initialization
1811 // (but don't do it if property is somewhat uninitialized)
1812 wxVariant defVal = GetDefaultValue();
1813 if ( defVal.IsNull() )
1814 return false;
1815
1816 SetValue(defVal);
1817 }
1818
1819 return true;
1820 }
1821
1822
1823 const wxPGEditor* wxPGProperty::GetEditorClass() const
1824 {
1825 const wxPGEditor* editor;
1826
1827 if ( !m_customEditor )
1828 {
1829 editor = DoGetEditorClass();
1830 }
1831 else
1832 editor = m_customEditor;
1833
1834 //
1835 // Maybe override editor if common value specified
1836 if ( GetDisplayedCommonValueCount() )
1837 {
1838 // TextCtrlAndButton -> ComboBoxAndButton
1839 if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor)) )
1840 editor = wxPGEditor_ChoiceAndButton;
1841
1842 // TextCtrl -> ComboBox
1843 else if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlEditor)) )
1844 editor = wxPGEditor_ComboBox;
1845 }
1846
1847 return editor;
1848 }
1849
1850 bool wxPGProperty::HasVisibleChildren() const
1851 {
1852 unsigned int i;
1853
1854 for ( i=0; i<GetChildCount(); i++ )
1855 {
1856 wxPGProperty* child = Item(i);
1857
1858 if ( !child->HasFlag(wxPG_PROP_HIDDEN) )
1859 return true;
1860 }
1861
1862 return false;
1863 }
1864
1865 bool wxPGProperty::RecreateEditor()
1866 {
1867 wxPropertyGrid* pg = GetGrid();
1868 wxASSERT(pg);
1869
1870 wxPGProperty* selected = pg->GetSelection();
1871 if ( this == selected )
1872 {
1873 pg->DoSelectProperty(this, wxPG_SEL_FORCE);
1874 return true;
1875 }
1876 return false;
1877 }
1878
1879
1880 void wxPGProperty::SetValueImage( wxBitmap& bmp )
1881 {
1882 delete m_valueBitmap;
1883
1884 if ( &bmp && bmp.Ok() )
1885 {
1886 // Resize the image
1887 wxSize maxSz = GetGrid()->GetImageSize();
1888 wxSize imSz(bmp.GetWidth(),bmp.GetHeight());
1889
1890 if ( imSz.x != maxSz.x || imSz.y != maxSz.y )
1891 {
1892 // Create a memory DC
1893 wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth());
1894
1895 wxMemoryDC dc;
1896 dc.SelectObject(*bmpNew);
1897
1898 // Scale
1899 // FIXME: This is ugly - use image or wait for scaling patch.
1900 double scaleX = (double)maxSz.x / (double)imSz.x;
1901 double scaleY = (double)maxSz.y / (double)imSz.y;
1902
1903 dc.SetUserScale(scaleX,scaleY);
1904
1905 dc.DrawBitmap( bmp, 0, 0 );
1906
1907 m_valueBitmap = bmpNew;
1908 }
1909 else
1910 {
1911 m_valueBitmap = new wxBitmap(bmp);
1912 }
1913
1914 m_flags |= wxPG_PROP_CUSTOMIMAGE;
1915 }
1916 else
1917 {
1918 m_valueBitmap = NULL;
1919 m_flags &= ~(wxPG_PROP_CUSTOMIMAGE);
1920 }
1921 }
1922
1923
1924 wxPGProperty* wxPGProperty::GetMainParent() const
1925 {
1926 const wxPGProperty* curChild = this;
1927 const wxPGProperty* curParent = m_parent;
1928
1929 while ( curParent && !curParent->IsCategory() )
1930 {
1931 curChild = curParent;
1932 curParent = curParent->m_parent;
1933 }
1934
1935 return (wxPGProperty*) curChild;
1936 }
1937
1938
1939 const wxPGProperty* wxPGProperty::GetLastVisibleSubItem() const
1940 {
1941 //
1942 // Returns last visible sub-item, recursively.
1943 if ( !IsExpanded() || !GetChildCount() )
1944 return this;
1945
1946 return Last()->GetLastVisibleSubItem();
1947 }
1948
1949
1950 bool wxPGProperty::IsVisible() const
1951 {
1952 const wxPGProperty* parent;
1953
1954 if ( HasFlag(wxPG_PROP_HIDDEN) )
1955 return false;
1956
1957 for ( parent = GetParent(); parent != NULL; parent = parent->GetParent() )
1958 {
1959 if ( !parent->IsExpanded() || parent->HasFlag(wxPG_PROP_HIDDEN) )
1960 return false;
1961 }
1962
1963 return true;
1964 }
1965
1966 wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const
1967 {
1968 wxPropertyGridPageState* state = GetParentState();
1969 wxPropertyGrid* propGrid = state->GetGrid();
1970 if ( state == propGrid->GetState() )
1971 return propGrid;
1972 return NULL;
1973 }
1974
1975
1976 int wxPGProperty::GetY2( int lh ) const
1977 {
1978 const wxPGProperty* parent;
1979 const wxPGProperty* child = this;
1980
1981 int y = 0;
1982
1983 for ( parent = GetParent(); parent != NULL; parent = child->GetParent() )
1984 {
1985 if ( !parent->IsExpanded() )
1986 return -1;
1987 y += parent->GetChildrenHeight(lh, child->GetIndexInParent());
1988 y += lh;
1989 child = parent;
1990 }
1991
1992 y -= lh; // need to reduce one level
1993
1994 return y;
1995 }
1996
1997
1998 int wxPGProperty::GetY() const
1999 {
2000 return GetY2(GetGrid()->GetRowHeight());
2001 }
2002
2003 // This is used by Insert etc.
2004 void wxPGProperty::AddChild2( wxPGProperty* prop, int index, bool correct_mode )
2005 {
2006 if ( index < 0 || (size_t)index >= m_children.size() )
2007 {
2008 if ( correct_mode ) prop->m_arrIndex = m_children.size();
2009 m_children.push_back( prop );
2010 }
2011 else
2012 {
2013 m_children.insert( m_children.begin()+index, prop);
2014 if ( correct_mode ) FixIndicesOfChildren( index );
2015 }
2016
2017 prop->m_parent = this;
2018 }
2019
2020 // This is used by properties that have fixed sub-properties
2021 void wxPGProperty::AddChild( wxPGProperty* prop )
2022 {
2023 wxASSERT_MSG( prop->GetBaseName().length(),
2024 "Property's children must have unique, non-empty names within their scope" );
2025
2026 prop->m_arrIndex = m_children.size();
2027 m_children.push_back( prop );
2028
2029 int custImgHeight = prop->OnMeasureImage().y;
2030 if ( custImgHeight < 0 /*|| custImgHeight > 1*/ )
2031 prop->m_flags |= wxPG_PROP_CUSTOMIMAGE;
2032
2033 prop->m_parent = this;
2034 }
2035
2036 void wxPGProperty::RemoveChild( wxPGProperty* p )
2037 {
2038 wxArrayPGProperty::iterator it;
2039 wxArrayPGProperty& children = m_children;
2040
2041 for ( it=children.begin(); it != children.end(); it++ )
2042 {
2043 if ( *it == p )
2044 {
2045 m_children.erase(it);
2046 break;
2047 }
2048 }
2049 }
2050
2051 void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const
2052 {
2053 wxASSERT( GetChildCount() );
2054 wxASSERT( !IsCategory() );
2055
2056 *value = GetValue();
2057
2058 if ( !list.GetCount() )
2059 return;
2060
2061 wxASSERT( GetChildCount() >= (unsigned int)list.GetCount() );
2062
2063 bool allChildrenSpecified;
2064
2065 // Don't fully update aggregate properties unless all children have
2066 // specified value
2067 if ( HasFlag(wxPG_PROP_AGGREGATE) )
2068 allChildrenSpecified = AreAllChildrenSpecified(&list);
2069 else
2070 allChildrenSpecified = true;
2071
2072 wxVariant childValue = list[0];
2073 unsigned int i;
2074 unsigned int n = 0;
2075
2076 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
2077
2078 for ( i=0; i<GetChildCount(); i++ )
2079 {
2080 const wxPGProperty* child = Item(i);
2081
2082 if ( childValue.GetName() == child->GetBaseName() )
2083 {
2084 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2085
2086 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
2087 {
2088 wxVariant cv2(child->GetValue());
2089 child->AdaptListToValue(childValue, &cv2);
2090 childValue = cv2;
2091 }
2092
2093 if ( allChildrenSpecified )
2094 ChildChanged(*value, i, childValue);
2095 n++;
2096 if ( n == (unsigned int)list.GetCount() )
2097 break;
2098 childValue = list[n];
2099 }
2100 }
2101 }
2102
2103
2104 void wxPGProperty::FixIndicesOfChildren( unsigned int starthere )
2105 {
2106 size_t i;
2107 for ( i=starthere;i<GetChildCount();i++)
2108 Item(i)->m_arrIndex = i;
2109 }
2110
2111
2112 // Returns (direct) child property with given name (or NULL if not found)
2113 wxPGProperty* wxPGProperty::GetPropertyByName( const wxString& name ) const
2114 {
2115 size_t i;
2116
2117 for ( i=0; i<GetChildCount(); i++ )
2118 {
2119 wxPGProperty* p = Item(i);
2120 if ( p->m_name == name )
2121 return p;
2122 }
2123
2124 // Does it have point, then?
2125 int pos = name.Find(wxS('.'));
2126 if ( pos <= 0 )
2127 return (wxPGProperty*) NULL;
2128
2129 wxPGProperty* p = GetPropertyByName(name. substr(0,pos));
2130
2131 if ( !p || !p->GetChildCount() )
2132 return NULL;
2133
2134 return p->GetPropertyByName(name.substr(pos+1,name.length()-pos-1));
2135 }
2136
2137 wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const
2138 {
2139 unsigned int i = hintIndex;
2140
2141 if ( i >= GetChildCount() )
2142 i = 0;
2143
2144 unsigned int lastIndex = i - 1;
2145
2146 if ( lastIndex >= GetChildCount() )
2147 lastIndex = GetChildCount() - 1;
2148
2149 for (;;)
2150 {
2151 wxPGProperty* p = Item(i);
2152 if ( p->m_name == name )
2153 return p;
2154
2155 if ( i == lastIndex )
2156 break;
2157
2158 i++;
2159 if ( i == GetChildCount() )
2160 i = 0;
2161 };
2162
2163 return NULL;
2164 }
2165
2166 int wxPGProperty::GetChildrenHeight( int lh, int iMax_ ) const
2167 {
2168 // Returns height of children, recursively, and
2169 // by taking expanded/collapsed status into account.
2170 //
2171 // iMax is used when finding property y-positions.
2172 //
2173 unsigned int i = 0;
2174 int h = 0;
2175
2176 if ( iMax_ == -1 )
2177 iMax_ = GetChildCount();
2178
2179 unsigned int iMax = iMax_;
2180
2181 wxASSERT( iMax <= GetChildCount() );
2182
2183 if ( !IsExpanded() && GetParent() )
2184 return 0;
2185
2186 while ( i < iMax )
2187 {
2188 wxPGProperty* pwc = (wxPGProperty*) Item(i);
2189
2190 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2191 {
2192 if ( !pwc->IsExpanded() ||
2193 pwc->GetChildCount() == 0 )
2194 h += lh;
2195 else
2196 h += pwc->GetChildrenHeight(lh) + lh;
2197 }
2198
2199 i++;
2200 }
2201
2202 return h;
2203 }
2204
2205 wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y, unsigned int lh, unsigned int* nextItemY ) const
2206 {
2207 wxASSERT( nextItemY );
2208
2209 // Linear search at the moment
2210 //
2211 // nextItemY = y of next visible property, final value will be written back.
2212 wxPGProperty* result = NULL;
2213 wxPGProperty* current = NULL;
2214 unsigned int iy = *nextItemY;
2215 unsigned int i = 0;
2216 unsigned int iMax = GetChildCount();
2217
2218 while ( i < iMax )
2219 {
2220 wxPGProperty* pwc = Item(i);
2221
2222 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2223 {
2224 // Found?
2225 if ( y < iy )
2226 {
2227 result = current;
2228 break;
2229 }
2230
2231 iy += lh;
2232
2233 if ( pwc->IsExpanded() &&
2234 pwc->GetChildCount() > 0 )
2235 {
2236 result = (wxPGProperty*) pwc->GetItemAtY( y, lh, &iy );
2237 if ( result )
2238 break;
2239 }
2240
2241 current = pwc;
2242 }
2243
2244 i++;
2245 }
2246
2247 // Found?
2248 if ( !result && y < iy )
2249 result = current;
2250
2251 *nextItemY = iy;
2252
2253 /*
2254 if ( current )
2255 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
2256 else
2257 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
2258 */
2259
2260 return (wxPGProperty*) result;
2261 }
2262
2263 void wxPGProperty::Empty()
2264 {
2265 size_t i;
2266 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES) )
2267 {
2268 for ( i=0; i<GetChildCount(); i++ )
2269 {
2270 delete m_children[i];
2271 }
2272 }
2273
2274 m_children.clear();
2275 }
2276
2277 void wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
2278 int WXUNUSED(childIndex),
2279 wxVariant& WXUNUSED(childValue) ) const
2280 {
2281 }
2282
2283 bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const
2284 {
2285 unsigned int i;
2286
2287 const wxVariantList* pList = NULL;
2288 wxVariantList::const_iterator node;
2289
2290 if ( pendingList )
2291 {
2292 pList = &pendingList->GetList();
2293 node = pList->begin();
2294 }
2295
2296 for ( i=0; i<GetChildCount(); i++ )
2297 {
2298 wxPGProperty* child = Item(i);
2299 const wxVariant* listValue = NULL;
2300 wxVariant value;
2301
2302 if ( pendingList )
2303 {
2304 const wxString& childName = child->GetBaseName();
2305
2306 for ( ; node != pList->end(); ++node )
2307 {
2308 const wxVariant& item = *((const wxVariant*)*node);
2309 if ( item.GetName() == childName )
2310 {
2311 listValue = &item;
2312 value = item;
2313 break;
2314 }
2315 }
2316 }
2317
2318 if ( !listValue )
2319 value = child->GetValue();
2320
2321 if ( value.IsNull() )
2322 return false;
2323
2324 // Check recursively
2325 if ( child->GetChildCount() )
2326 {
2327 const wxVariant* childList = NULL;
2328
2329 if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST )
2330 childList = listValue;
2331
2332 if ( !child->AreAllChildrenSpecified((wxVariant*)childList) )
2333 return false;
2334 }
2335 }
2336
2337 return true;
2338 }
2339
2340 wxPGProperty* wxPGProperty::UpdateParentValues()
2341 {
2342 wxPGProperty* parent = m_parent;
2343 if ( parent && parent->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
2344 !parent->IsCategory() && !parent->IsRoot() )
2345 {
2346 wxString s;
2347 parent->DoGenerateComposedValue(s);
2348 parent->m_value = s;
2349 return parent->UpdateParentValues();
2350 }
2351 return this;
2352 }
2353
2354 bool wxPGProperty::IsTextEditable() const
2355 {
2356 if ( HasFlag(wxPG_PROP_READONLY) )
2357 return false;
2358
2359 if ( HasFlag(wxPG_PROP_NOEDITOR) &&
2360 (GetChildCount() ||
2361 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2362 )
2363 return false;
2364
2365 return true;
2366 }
2367
2368 // Call after fixed sub-properties added/removed after creation.
2369 // if oldSelInd >= 0 and < new max items, then selection is
2370 // moved to it. Note: oldSelInd -2 indicates that this property
2371 // should be selected.
2372 void wxPGProperty::SubPropsChanged( int oldSelInd )
2373 {
2374 wxPropertyGridPageState* state = GetParentState();
2375 wxPropertyGrid* grid = state->GetGrid();
2376
2377 //
2378 // Re-repare children (recursively)
2379 for ( unsigned int i=0; i<GetChildCount(); i++ )
2380 {
2381 wxPGProperty* child = Item(i);
2382 child->InitAfterAdded(state, grid);
2383 }
2384
2385 wxPGProperty* sel = (wxPGProperty*) NULL;
2386 if ( oldSelInd >= (int)m_children.size() )
2387 oldSelInd = (int)m_children.size() - 1;
2388
2389 if ( oldSelInd >= 0 )
2390 sel = m_children[oldSelInd];
2391 else if ( oldSelInd == -2 )
2392 sel = this;
2393
2394 if ( sel )
2395 state->DoSelectProperty(sel);
2396
2397 if ( state == grid->GetState() )
2398 {
2399 grid->GetPanel()->Refresh();
2400 }
2401 }
2402
2403 // -----------------------------------------------------------------------
2404 // wxPGRootProperty
2405 // -----------------------------------------------------------------------
2406
2407 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2408 IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2409
2410
2411 wxPGRootProperty::wxPGRootProperty()
2412 : wxPGProperty()
2413 {
2414 #ifdef __WXDEBUG__
2415 m_name = wxS("<root>");
2416 #endif
2417 SetParentalType(0);
2418 m_depth = 0;
2419 }
2420
2421
2422 wxPGRootProperty::~wxPGRootProperty()
2423 {
2424 }
2425
2426
2427 // -----------------------------------------------------------------------
2428 // wxPropertyCategory
2429 // -----------------------------------------------------------------------
2430
2431 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2432 IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2433
2434 void wxPropertyCategory::Init()
2435 {
2436 // don't set colour - prepareadditem method should do this
2437 SetParentalType(wxPG_PROP_CATEGORY);
2438 m_capFgColIndex = 1;
2439 m_textExtent = -1;
2440 }
2441
2442 wxPropertyCategory::wxPropertyCategory()
2443 : wxPGProperty()
2444 {
2445 Init();
2446 }
2447
2448
2449 wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2450 : wxPGProperty(label,name)
2451 {
2452 Init();
2453 }
2454
2455
2456 wxPropertyCategory::~wxPropertyCategory()
2457 {
2458 }
2459
2460
2461 wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value),
2462 int WXUNUSED(argFlags) ) const
2463 {
2464 return wxEmptyString;
2465 }
2466
2467 int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const
2468 {
2469 if ( m_textExtent > 0 )
2470 return m_textExtent;
2471 int x = 0, y = 0;
2472 ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2473 return x;
2474 }
2475
2476 void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font )
2477 {
2478 int x = 0, y = 0;
2479 wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2480 m_textExtent = x;
2481 }
2482
2483 // -----------------------------------------------------------------------
2484 // wxPGAttributeStorage
2485 // -----------------------------------------------------------------------
2486
2487 wxPGAttributeStorage::wxPGAttributeStorage()
2488 {
2489 }
2490
2491 wxPGAttributeStorage::~wxPGAttributeStorage()
2492 {
2493 wxPGHashMapS2P::iterator it;
2494
2495 for ( it = m_map.begin(); it != m_map.end(); ++it )
2496 {
2497 wxVariantData* data = (wxVariantData*) it->second;
2498 data->DecRef();
2499 }
2500 }
2501
2502 void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value )
2503 {
2504 wxVariantData* data = value.GetData();
2505
2506 // Free old, if any
2507 wxPGHashMapS2P::iterator it = m_map.find(name);
2508 if ( it != m_map.end() )
2509 {
2510 ((wxVariantData*)it->second)->DecRef();
2511
2512 if ( !data )
2513 {
2514 // If Null variant, just remove from set
2515 m_map.erase(it);
2516 return;
2517 }
2518 }
2519
2520 if ( data )
2521 {
2522 data->IncRef();
2523
2524 m_map[name] = data;
2525 }
2526 }
2527
2528 #endif // wxUSE_PROPGRID