Removed #include <typeinfo> (since C++ RTTI is no longer used)
[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/button.h"
33 #include "wx/pen.h"
34 #include "wx/brush.h"
35 #include "wx/cursor.h"
36 #include "wx/dialog.h"
37 #include "wx/settings.h"
38 #include "wx/msgdlg.h"
39 #include "wx/choice.h"
40 #include "wx/stattext.h"
41 #include "wx/scrolwin.h"
42 #include "wx/dirdlg.h"
43 #include "wx/layout.h"
44 #include "wx/sizer.h"
45 #include "wx/textdlg.h"
46 #include "wx/filedlg.h"
47 #include "wx/statusbr.h"
48 #include "wx/intl.h"
49 #include "wx/frame.h"
50 #endif
51
52 #include <wx/propgrid/propgrid.h>
53
54
55 #define PWC_CHILD_SUMMARY_LIMIT 16 // Maximum number of children summarized in a parent property's
56 // value field.
57
58 #define PWC_CHILD_SUMMARY_CHAR_LIMIT 64 // Character limit of summary field when not editing
59
60
61 // -----------------------------------------------------------------------
62
63 static void wxPGDrawFocusRect( wxDC& dc, const wxRect& rect )
64 {
65 #if defined(__WXMSW__) && !defined(__WXWINCE__)
66 // FIXME: Use DrawFocusRect code above (currently it draws solid line
67 // for caption focus but works ok for other stuff).
68 // Also, it seems that this code may not work in future wx versions.
69 dc.SetLogicalFunction(wxINVERT);
70
71 wxPen pen(*wxBLACK,1,wxDOT);
72 pen.SetCap(wxCAP_BUTT);
73 dc.SetPen(pen);
74 dc.SetBrush(*wxTRANSPARENT_BRUSH);
75
76 dc.DrawRectangle(rect);
77
78 dc.SetLogicalFunction(wxCOPY);
79 #else
80 dc.SetLogicalFunction(wxINVERT);
81
82 dc.SetPen(wxPen(*wxBLACK,1,wxDOT));
83 dc.SetBrush(*wxTRANSPARENT_BRUSH);
84
85 dc.DrawRectangle(rect);
86
87 dc.SetLogicalFunction(wxCOPY);
88 #endif
89 }
90
91 // -----------------------------------------------------------------------
92 // wxPGCellRenderer
93 // -----------------------------------------------------------------------
94
95 wxSize wxPGCellRenderer::GetImageSize( const wxPGProperty* WXUNUSED(property),
96 int WXUNUSED(column),
97 int WXUNUSED(item) ) const
98 {
99 return wxSize(0, 0);
100 }
101
102 void wxPGCellRenderer::DrawText( wxDC& dc, const wxRect& rect,
103 int xOffset, const wxString& text ) const
104 {
105 if ( xOffset )
106 xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
107 dc.DrawText( text,
108 rect.x+xOffset+wxPG_XBEFORETEXT,
109 rect.y+((rect.height-dc.GetCharHeight())/2) );
110 }
111
112 void wxPGCellRenderer::DrawEditorValue( wxDC& dc, const wxRect& rect,
113 int xOffset, const wxString& text,
114 wxPGProperty* property,
115 const wxPGEditor* editor ) const
116 {
117 if ( xOffset )
118 xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
119
120 int yOffset = ((rect.height-dc.GetCharHeight())/2);
121
122 if ( editor )
123 {
124 wxRect rect2(rect);
125 rect2.x += xOffset;
126 rect2.y += yOffset;
127 rect2.height -= yOffset;
128 editor->DrawValue( dc, rect2, property, text );
129 }
130 else
131 {
132 dc.DrawText( text,
133 rect.x+xOffset+wxPG_XBEFORETEXT,
134 rect.y+yOffset );
135 }
136 }
137
138 void wxPGCellRenderer::DrawCaptionSelectionRect( wxDC& dc, int x, int y, int w, int h ) const
139 {
140 wxRect focusRect(x,y+((h-dc.GetCharHeight())/2),w,h);
141 wxPGDrawFocusRect(dc,focusRect);
142 }
143
144 int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& cell, int flags ) const
145 {
146 int imageOffset = 0;
147
148 if ( !(flags & Selected) )
149 {
150 // Draw using wxPGCell information, if available
151 wxColour fgCol = cell.GetFgCol();
152 if ( fgCol.Ok() )
153 dc.SetTextForeground(fgCol);
154
155 wxColour bgCol = cell.GetBgCol();
156 if ( bgCol.Ok() )
157 {
158 dc.SetPen(bgCol);
159 dc.SetBrush(bgCol);
160 dc.DrawRectangle(rect);
161 }
162 }
163
164 const wxBitmap& bmp = cell.GetBitmap();
165 if ( bmp.Ok() &&
166 // In control, do not draw oversized bitmap
167 (!(flags & Control) || bmp.GetHeight() < rect.height )
168 )
169 {
170 dc.DrawBitmap( bmp,
171 rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
172 rect.y + wxPG_CUSTOM_IMAGE_SPACINGY,
173 true );
174 imageOffset = bmp.GetWidth();
175 }
176
177 return imageOffset;
178 }
179
180 // -----------------------------------------------------------------------
181 // wxPGDefaultRenderer
182 // -----------------------------------------------------------------------
183
184 void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect,
185 const wxPropertyGrid* propertyGrid, wxPGProperty* property,
186 int column, int item, int flags ) const
187 {
188 bool isUnspecified = property->IsValueUnspecified();
189
190 if ( column == 1 && item == -1 )
191 {
192 int cmnVal = property->GetCommonValue();
193 if ( cmnVal >= 0 )
194 {
195 // Common Value
196 if ( !isUnspecified )
197 DrawText( dc, rect, 0, propertyGrid->GetCommonValueLabel(cmnVal) );
198 return;
199 }
200 }
201
202 const wxPGEditor* editor = NULL;
203 const wxPGCell* cell = property->GetCell(column);
204
205 wxString text;
206 int imageOffset = 0;
207
208 // Use choice cell?
209 if ( column == 1 && (flags & Control) )
210 {
211 int selectedIndex = property->GetChoiceSelection();
212 if ( selectedIndex != wxNOT_FOUND )
213 {
214 const wxPGChoices& choices = property->GetChoices();
215 const wxPGCell* ccell = &choices[selectedIndex];
216 if ( ccell &&
217 ( ccell->GetBitmap().IsOk() || ccell->GetFgCol().IsOk() || ccell->GetBgCol().IsOk() )
218 )
219 cell = ccell;
220 }
221 }
222
223 if ( cell )
224 {
225 int preDrawFlags = flags;
226
227 if ( propertyGrid->GetInternalFlags() & wxPG_FL_CELL_OVERRIDES_SEL )
228 preDrawFlags = preDrawFlags & ~(Selected);
229
230 imageOffset = PreDrawCell( dc, rect, *cell, preDrawFlags );
231 text = cell->GetText();
232 if ( text == wxS("@!") )
233 {
234 if ( column == 0 )
235 text = property->GetLabel();
236 else if ( column == 1 )
237 text = property->GetValueString();
238 else
239 text = wxEmptyString;
240 }
241 }
242 else if ( column == 0 )
243 {
244 // Caption
245 DrawText( dc, rect, 0, property->GetLabel() );
246 }
247 else if ( column == 1 )
248 {
249 if ( !isUnspecified )
250 {
251 editor = property->GetColumnEditor(column);
252
253 // Regular property value
254
255 wxSize imageSize = propertyGrid->GetImageSize(property, item);
256
257 wxPGPaintData paintdata;
258 paintdata.m_parent = propertyGrid;
259 paintdata.m_choiceItem = item;
260
261 if ( imageSize.x > 0 )
262 {
263 wxRect imageRect(rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
264 rect.y+wxPG_CUSTOM_IMAGE_SPACINGY,
265 wxPG_CUSTOM_IMAGE_WIDTH,
266 rect.height-(wxPG_CUSTOM_IMAGE_SPACINGY*2));
267
268 /*if ( imageSize.x == wxPG_FULL_CUSTOM_PAINT_WIDTH )
269 {
270 imageRect.width = m_width - imageRect.x;
271 }*/
272
273 dc.SetPen( wxPen(propertyGrid->GetCellTextColour(), 1, wxSOLID) );
274
275 paintdata.m_drawnWidth = imageSize.x;
276 paintdata.m_drawnHeight = imageSize.y;
277
278 if ( !isUnspecified )
279 {
280 property->OnCustomPaint( dc, imageRect, paintdata );
281 }
282 else
283 {
284 dc.SetBrush(*wxWHITE_BRUSH);
285 dc.DrawRectangle(imageRect);
286 }
287
288 imageOffset = paintdata.m_drawnWidth;
289 }
290
291 text = property->GetValueString();
292
293 // Add units string?
294 if ( propertyGrid->GetColumnCount() <= 2 )
295 {
296 wxString unitsString = property->GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
297 if ( unitsString.length() )
298 text = wxString::Format(wxS("%s %s"), text.c_str(), unitsString.c_str() );
299 }
300 }
301
302 if ( text.length() == 0 )
303 {
304 // Try to show inline help if no text
305 wxVariant vInlineHelp = property->GetAttribute(wxPGGlobalVars->m_strInlineHelp);
306 if ( !vInlineHelp.IsNull() )
307 {
308 text = vInlineHelp.GetString();
309 dc.SetTextForeground(propertyGrid->GetCellDisabledTextColour());
310 }
311 }
312 }
313 else if ( column == 2 )
314 {
315 // Add units string?
316 if ( !text.length() )
317 text = property->GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
318 }
319
320 DrawEditorValue( dc, rect, imageOffset, text, property, editor );
321
322 // active caption gets nice dotted rectangle
323 if ( property->IsCategory() /*&& column == 0*/ )
324 {
325 if ( flags & Selected )
326 {
327 if ( imageOffset > 0 )
328 imageOffset += wxCC_CUSTOM_IMAGE_MARGIN2 + 4;
329
330 DrawCaptionSelectionRect( dc,
331 rect.x+wxPG_XBEFORETEXT-wxPG_CAPRECTXMARGIN+imageOffset,
332 rect.y-wxPG_CAPRECTYMARGIN+1,
333 ((wxPropertyCategory*)property)->GetTextExtent(propertyGrid,
334 propertyGrid->GetCaptionFont())
335 +(wxPG_CAPRECTXMARGIN*2),
336 propertyGrid->GetFontHeight()+(wxPG_CAPRECTYMARGIN*2) );
337 }
338 }
339 }
340
341 wxSize wxPGDefaultRenderer::GetImageSize( const wxPGProperty* property,
342 int column,
343 int item ) const
344 {
345 if ( property && column == 1 )
346 {
347 if ( item == -1 )
348 {
349 wxBitmap* bmp = property->GetValueImage();
350
351 if ( bmp && bmp->Ok() )
352 return wxSize(bmp->GetWidth(),bmp->GetHeight());
353 }
354 }
355 return wxSize(0,0);
356 }
357
358 // -----------------------------------------------------------------------
359 // wxPGCell
360 // -----------------------------------------------------------------------
361
362 wxPGCell::wxPGCell()
363 {
364 }
365
366 wxPGCell::wxPGCell( const wxString& text,
367 const wxBitmap& bitmap,
368 const wxColour& fgCol,
369 const wxColour& bgCol )
370 : m_bitmap(bitmap), m_fgCol(fgCol), m_bgCol(bgCol)
371 {
372 m_text = text;
373 }
374
375 // -----------------------------------------------------------------------
376 // wxPGProperty
377 // -----------------------------------------------------------------------
378
379 IMPLEMENT_ABSTRACT_CLASS(wxPGProperty, wxObject)
380
381 wxString* wxPGProperty::sm_wxPG_LABEL = NULL;
382
383 void wxPGProperty::Init()
384 {
385 m_commonValue = -1;
386 m_arrIndex = 0xFFFF;
387 m_parent = NULL;
388
389 m_parentState = (wxPropertyGridPageState*) NULL;
390
391 m_clientData = NULL;
392 m_clientObject = NULL;
393
394 m_customEditor = (wxPGEditor*) NULL;
395 #if wxUSE_VALIDATORS
396 m_validator = (wxValidator*) NULL;
397 #endif
398 m_valueBitmap = (wxBitmap*) NULL;
399
400 m_maxLen = 0; // infinite maximum length
401
402 m_flags = wxPG_PROP_PROPERTY;
403
404 m_depth = 1;
405 m_bgColIndex = 0;
406 m_fgColIndex = 0;
407
408 SetExpanded(true);
409 }
410
411
412 void wxPGProperty::Init( const wxString& label, const wxString& name )
413 {
414 // We really need to check if &label and &name are NULL pointers
415 // (this can if we are called before property grid has been initalized)
416
417 if ( (&label) != NULL && label != wxPG_LABEL )
418 m_label = label;
419
420 if ( (&name) != NULL && name != wxPG_LABEL )
421 DoSetName( name );
422 else
423 DoSetName( m_label );
424
425 Init();
426 }
427
428 wxPGProperty::wxPGProperty()
429 : wxObject()
430 {
431 Init();
432 }
433
434
435 wxPGProperty::wxPGProperty( const wxString& label, const wxString& name )
436 : wxObject()
437 {
438 Init( label, name );
439 }
440
441
442 wxPGProperty::~wxPGProperty()
443 {
444 delete m_clientObject;
445
446 Empty(); // this deletes items
447
448 delete m_valueBitmap;
449 #if wxUSE_VALIDATORS
450 delete m_validator;
451 #endif
452
453 unsigned int i;
454
455 for ( i=0; i<m_cells.size(); i++ )
456 delete (wxPGCell*) m_cells[i];
457
458 // This makes it easier for us to detect dangling pointers
459 m_parent = NULL;
460 }
461
462
463 bool wxPGProperty::IsSomeParent( wxPGProperty* candidate ) const
464 {
465 wxPGProperty* parent = m_parent;
466 do
467 {
468 if ( parent == candidate )
469 return true;
470 parent = parent->m_parent;
471 } while ( parent );
472 return false;
473 }
474
475
476 wxString wxPGProperty::GetName() const
477 {
478 wxPGProperty* parent = GetParent();
479
480 if ( !m_name.length() || !parent || parent->IsCategory() || parent->IsRoot() )
481 return m_name;
482
483 return m_parent->GetName() + wxS(".") + m_name;
484 }
485
486 wxPropertyGrid* wxPGProperty::GetGrid() const
487 {
488 if ( !m_parentState )
489 return NULL;
490 return m_parentState->GetGrid();
491 }
492
493
494 void wxPGProperty::UpdateControl( wxWindow* primary )
495 {
496 if ( primary )
497 GetEditorClass()->UpdateControl(this, primary);
498 }
499
500 bool wxPGProperty::ValidateValue( wxVariant& WXUNUSED(value), wxPGValidationInfo& WXUNUSED(validationInfo) ) const
501 {
502 return true;
503 }
504
505 void wxPGProperty::OnSetValue()
506 {
507 }
508
509 void wxPGProperty::RefreshChildren ()
510 {
511 }
512
513 wxString wxPGProperty::GetColumnText( unsigned int col ) const
514 {
515 wxPGCell* cell = GetCell(col);
516 if ( cell )
517 {
518 return cell->GetText();
519 }
520 else
521 {
522 if ( col == 0 )
523 return GetLabel();
524 else if ( col == 1 )
525 return GetDisplayedString();
526 else if ( col == 2 )
527 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
528 }
529
530 return wxEmptyString;
531 }
532
533 void wxPGProperty::GenerateComposedValue( wxString& text, int argFlags ) const
534 {
535 int i;
536 int iMax = m_children.GetCount();
537
538 text.clear();
539 if ( iMax == 0 )
540 return;
541
542 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
543 !(argFlags & wxPG_FULL_VALUE) )
544 iMax = PWC_CHILD_SUMMARY_LIMIT;
545
546 int iMaxMinusOne = iMax-1;
547
548 if ( !IsTextEditable() )
549 argFlags |= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT;
550
551 wxPGProperty* curChild = (wxPGProperty*) m_children.Item(0);
552
553 for ( i = 0; i < iMax; i++ )
554 {
555 wxString s;
556 if ( !curChild->IsValueUnspecified() )
557 s = curChild->GetValueString(argFlags|wxPG_COMPOSITE_FRAGMENT);
558
559 bool skip = false;
560 if ( (argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT) && !s.length() )
561 skip = true;
562
563 if ( !curChild->GetChildCount() || skip )
564 text += s;
565 else
566 text += wxS("[") + s + wxS("]");
567
568 if ( i < iMaxMinusOne )
569 {
570 if ( text.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT &&
571 !(argFlags & wxPG_EDITABLE_VALUE) &&
572 !(argFlags & wxPG_FULL_VALUE) )
573 break;
574
575 if ( !skip )
576 {
577 if ( !curChild->GetChildCount() )
578 text += wxS("; ");
579 else
580 text += wxS(" ");
581 }
582
583 curChild = (wxPGProperty*) m_children.Item(i+1);
584 }
585 }
586
587 // Remove superfluous semicolon and space
588 wxString rest;
589 if ( text.EndsWith(wxS("; "), &rest) )
590 text = rest;
591
592 if ( (unsigned int)i < m_children.GetCount() )
593 text += wxS("; ...");
594 }
595
596 wxString wxPGProperty::GetValueAsString( int argFlags ) const
597 {
598 wxCHECK_MSG( GetChildCount() > 0,
599 wxString(),
600 wxT("If user property does not have any children, it must override GetValueAsString") );
601
602 wxString text;
603 GenerateComposedValue(text, argFlags);
604 return text;
605 }
606
607 wxString wxPGProperty::GetValueString( int argFlags ) const
608 {
609 if ( IsValueUnspecified() )
610 return wxEmptyString;
611
612 if ( m_commonValue == -1 )
613 return GetValueAsString(argFlags);
614
615 //
616 // Return common value's string representation
617 wxPropertyGrid* pg = GetGrid();
618 const wxPGCommonValue* cv = pg->GetCommonValue(m_commonValue);
619
620 if ( argFlags & wxPG_FULL_VALUE )
621 {
622 return cv->GetLabel();
623 }
624 else if ( argFlags & wxPG_EDITABLE_VALUE )
625 {
626 return cv->GetEditableText();
627 }
628 else
629 {
630 return cv->GetLabel();
631 }
632 }
633
634 bool wxPGProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const
635 {
636 variant = (long)number;
637 return true;
638 }
639
640 // Convert semicolon delimited tokens into child values.
641 bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
642 {
643 if ( !GetChildCount() )
644 return false;
645
646 unsigned int curChild = 0;
647
648 unsigned int iMax = m_children.GetCount();
649
650 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
651 !(argFlags & wxPG_FULL_VALUE) )
652 iMax = PWC_CHILD_SUMMARY_LIMIT;
653
654 bool changed = false;
655
656 wxString token;
657 size_t pos = 0;
658
659 // Its best only to add non-empty group items
660 bool addOnlyIfNotEmpty = false;
661 const wxChar delimeter = wxS(';');
662
663 size_t tokenStart = 0xFFFFFF;
664
665 wxVariantList temp_list;
666 wxVariant list(temp_list);
667
668 int propagatedFlags = argFlags & wxPG_REPORT_ERROR;
669
670 #ifdef __WXDEBUG__
671 bool debug_print = false;
672 #endif
673
674 #ifdef __WXDEBUG__
675 if ( debug_print )
676 wxLogDebug(wxT(">> %s.StringToValue('%s')"),GetLabel().c_str(),text.c_str());
677 #endif
678
679 wxString::const_iterator it = text.begin();
680 wxUniChar a;
681
682 if ( it != text.end() )
683 a = *it;
684 else
685 a = 0;
686
687 for ( ;; )
688 {
689 if ( tokenStart != 0xFFFFFF )
690 {
691 // Token is running
692 if ( a == delimeter || a == 0 )
693 {
694 token = text.substr(tokenStart,pos-tokenStart);
695 token.Trim(true);
696 size_t len = token.length();
697
698 if ( !addOnlyIfNotEmpty || len > 0 )
699 {
700 const wxPGProperty* child = Item(curChild);
701 #ifdef __WXDEBUG__
702 if ( debug_print )
703 wxLogDebug(wxT("token = '%s', child = %s"),token.c_str(),child->GetLabel().c_str());
704 #endif
705
706 if ( len > 0 )
707 {
708 bool wasUnspecified = child->IsValueUnspecified();
709
710 wxVariant variant(child->GetValueRef());
711 if ( child->StringToValue(variant, token, propagatedFlags|wxPG_COMPOSITE_FRAGMENT) )
712 {
713 variant.SetName(child->GetBaseName());
714
715 // Clear unspecified flag only if OnSetValue() didn't
716 // affect it.
717 if ( child->IsValueUnspecified() &&
718 (wasUnspecified || !UsesAutoUnspecified()) )
719 {
720 variant = child->GetDefaultValue();
721 }
722
723 list.Append(variant);
724
725 changed = true;
726 }
727 }
728 else
729 {
730 // Empty, becomes unspecified
731 wxVariant variant2;
732 variant2.SetName(child->GetBaseName());
733 list.Append(variant2);
734 changed = true;
735 }
736
737 curChild++;
738 if ( curChild >= iMax )
739 break;
740 }
741
742 tokenStart = 0xFFFFFF;
743 }
744 }
745 else
746 {
747 // Token is not running
748 if ( a != wxS(' ') )
749 {
750
751 addOnlyIfNotEmpty = false;
752
753 // Is this a group of tokens?
754 if ( a == wxS('[') )
755 {
756 int depth = 1;
757
758 if ( it != text.end() ) it++;
759 pos++;
760 size_t startPos = pos;
761
762 // Group item - find end
763 while ( it != text.end() && depth > 0 )
764 {
765 a = *it;
766 it++;
767 pos++;
768
769 if ( a == wxS(']') )
770 depth--;
771 else if ( a == wxS('[') )
772 depth++;
773 }
774
775 token = text.substr(startPos,pos-startPos-1);
776
777 if ( !token.length() )
778 break;
779
780 const wxPGProperty* child = Item(curChild);
781
782 wxVariant oldChildValue = child->GetValue();
783 wxVariant variant(oldChildValue);
784 bool stvRes = child->StringToValue( variant, token, propagatedFlags );
785 if ( stvRes || (variant != oldChildValue) )
786 {
787 if ( stvRes )
788 changed = true;
789 }
790 else
791 {
792 // Failed, becomes unspecified
793 variant.MakeNull();
794 changed = true;
795 }
796
797 variant.SetName(child->GetBaseName());
798 list.Append(variant);
799
800 curChild++;
801 if ( curChild >= iMax )
802 break;
803
804 addOnlyIfNotEmpty = true;
805
806 tokenStart = 0xFFFFFF;
807 }
808 else
809 {
810 tokenStart = pos;
811
812 if ( a == delimeter )
813 {
814 pos--;
815 it--;
816 }
817 }
818 }
819 }
820
821 if ( a == 0 )
822 break;
823
824 it++;
825 if ( it != text.end() )
826 {
827 a = *it;
828 }
829 else
830 {
831 a = 0;
832 }
833 pos++;
834 }
835
836 if ( changed )
837 variant = list;
838
839 return changed;
840 }
841
842 bool wxPGProperty::SetValueFromString( const wxString& text, int argFlags )
843 {
844 wxVariant variant(m_value);
845 bool res = StringToValue(variant, text, argFlags);
846 if ( res )
847 SetValue(variant);
848 return res;
849 }
850
851 bool wxPGProperty::SetValueFromInt( long number, int argFlags )
852 {
853 wxVariant variant(m_value);
854 bool res = IntToValue(variant, number, argFlags);
855 if ( res )
856 SetValue(variant);
857 return res;
858 }
859
860 wxSize wxPGProperty::OnMeasureImage( int WXUNUSED(item) ) const
861 {
862 if ( m_valueBitmap )
863 return wxSize(m_valueBitmap->GetWidth(),-1);
864
865 return wxSize(0,0);
866 }
867
868 wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const
869 {
870 return wxPGGlobalVars->m_defaultRenderer;
871 }
872
873 void wxPGProperty::OnCustomPaint( wxDC& dc,
874 const wxRect& rect,
875 wxPGPaintData& )
876 {
877 wxBitmap* bmp = m_valueBitmap;
878
879 wxCHECK_RET( bmp && bmp->Ok(), wxT("invalid bitmap") );
880
881 wxCHECK_RET( rect.x >= 0, wxT("unexpected measure call") );
882
883 dc.DrawBitmap(*bmp,rect.x,rect.y);
884 }
885
886 const wxPGEditor* wxPGProperty::DoGetEditorClass() const
887 {
888 return wxPG_EDITOR(TextCtrl);
889 }
890
891 // Default extra property event handling - that is, none at all.
892 bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& )
893 {
894 return false;
895 }
896
897
898 void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags )
899 {
900 if ( !value.IsNull() )
901 {
902 wxVariant tempListVariant;
903
904 SetCommonValue(-1);
905 // List variants are reserved a special purpose
906 // as intermediate containers for child values
907 // of properties with children.
908 if ( value.GetType() == wxPG_VARIANT_TYPE_LIST )
909 {
910 //
911 // However, situation is different for composed string properties
912 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
913 {
914 tempListVariant = value;
915 pList = &tempListVariant;
916 }
917
918 wxVariant newValue;
919 AdaptListToValue(value, &newValue);
920 value = newValue;
921 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
922 }
923
924 if ( HasFlag( wxPG_PROP_AGGREGATE) )
925 flags |= wxPG_SETVAL_AGGREGATED;
926
927 if ( pList && !pList->IsNull() )
928 {
929 wxASSERT( pList->GetType() == wxPG_VARIANT_TYPE_LIST );
930 wxASSERT( GetChildCount() );
931 wxASSERT( !IsCategory() );
932
933 wxVariantList& list = pList->GetList();
934 wxVariantList::iterator node;
935 unsigned int i = 0;
936
937 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
938
939 // Children in list can be in any order, but we will give hint to
940 // GetPropertyByNameWH(). This optimizes for full list parsing.
941 for ( node = list.begin(); node != list.end(); node++ )
942 {
943 wxVariant& childValue = *((wxVariant*)*node);
944 wxPGProperty* child = GetPropertyByNameWH(childValue.GetName(), i);
945 if ( child )
946 {
947 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
948 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
949 {
950 if ( child->HasFlag(wxPG_PROP_AGGREGATE) && !(flags & wxPG_SETVAL_AGGREGATED) )
951 {
952 wxVariant listRefCopy = childValue;
953 child->SetValue(childValue, &listRefCopy, flags|wxPG_SETVAL_FROM_PARENT);
954 }
955 else
956 {
957 wxVariant oldVal = child->GetValue();
958 child->SetValue(oldVal, &childValue, flags|wxPG_SETVAL_FROM_PARENT);
959 }
960 }
961 else if ( child->GetValue() != childValue )
962 {
963 // For aggregate properties, we will trust RefreshChildren()
964 // to update child values.
965 if ( !HasFlag(wxPG_PROP_AGGREGATE) )
966 child->SetValue(childValue, NULL, flags|wxPG_SETVAL_FROM_PARENT);
967 if ( flags & wxPG_SETVAL_BY_USER )
968 child->SetFlag(wxPG_PROP_MODIFIED);
969 }
970 }
971 i++;
972 }
973 }
974
975 if ( !value.IsNull() )
976 {
977 m_value = value;
978 OnSetValue();
979
980 if ( !(flags & wxPG_SETVAL_FROM_PARENT) )
981 UpdateParentValues();
982 }
983
984 if ( flags & wxPG_SETVAL_BY_USER )
985 SetFlag(wxPG_PROP_MODIFIED);
986
987 if ( HasFlag(wxPG_PROP_AGGREGATE) )
988 RefreshChildren();
989 }
990 else
991 {
992 if ( m_commonValue != -1 )
993 {
994 wxPropertyGrid* pg = GetGrid();
995 if ( !pg || m_commonValue != pg->GetUnspecifiedCommonValue() )
996 SetCommonValue(-1);
997 }
998
999 m_value = value;
1000
1001 // Set children to unspecified, but only if aggregate or
1002 // value is <composed>
1003 if ( AreChildrenComponents() )
1004 {
1005 unsigned int i;
1006 for ( i=0; i<GetChildCount(); i++ )
1007 Item(i)->SetValue(value, NULL, flags|wxPG_SETVAL_FROM_PARENT);
1008 }
1009 }
1010
1011 //
1012 // Update editor control
1013 //
1014
1015 // We need to check for these, otherwise GetGrid() may fail.
1016 if ( flags & wxPG_SETVAL_REFRESH_EDITOR )
1017 RefreshEditor();
1018 }
1019
1020
1021 void wxPGProperty::SetValueInEvent( wxVariant value ) const
1022 {
1023 GetGrid()->ValueChangeInEvent(value);
1024 }
1025
1026 void wxPGProperty::SetFlagRecursively( FlagType flag, bool set )
1027 {
1028 if ( set )
1029 SetFlag(flag);
1030 else
1031 ClearFlag(flag);
1032
1033 unsigned int i;
1034 for ( i = 0; i < GetChildCount(); i++ )
1035 Item(i)->SetFlagRecursively(flag, set);
1036 }
1037
1038 void wxPGProperty::RefreshEditor()
1039 {
1040 if ( m_parent && GetParentState() )
1041 {
1042 wxPropertyGrid* pg = GetParentState()->GetGrid();
1043 if ( pg->GetSelectedProperty() == this )
1044 {
1045 wxWindow* editor = pg->GetEditorControl();
1046 if ( editor )
1047 GetEditorClass()->UpdateControl( this, editor );
1048 }
1049 }
1050 }
1051
1052
1053 wxVariant wxPGProperty::GetDefaultValue() const
1054 {
1055 wxVariant defVal = GetAttribute(wxS("DefaultValue"));
1056 if ( !defVal.IsNull() )
1057 return defVal;
1058
1059 wxVariant value = GetValue();
1060
1061 if ( !value.IsNull() )
1062 {
1063 wxString valueType(value.GetType());
1064
1065 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1066 return wxPGVariant_Zero;
1067 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1068 return wxPGVariant_EmptyString;
1069 if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1070 return wxPGVariant_False;
1071 if ( valueType == wxPG_VARIANT_TYPE_DOUBLE )
1072 return wxVariant(0.0);
1073 if ( valueType == wxPG_VARIANT_TYPE_ARRSTRING )
1074 return wxVariant(wxArrayString());
1075 if ( valueType == wxS("wxLongLong") )
1076 return WXVARIANT(wxLongLong(0));
1077 if ( valueType == wxS("wxULongLong") )
1078 return WXVARIANT(wxULongLong(0));
1079 if ( valueType == wxS("wxColour") )
1080 return WXVARIANT(*wxBLACK);
1081 #if wxUSE_DATETIME
1082 if ( valueType == wxPG_VARIANT_TYPE_DATETIME )
1083 return wxVariant(wxDateTime::Now());
1084 #endif
1085 if ( valueType == wxS("wxFont") )
1086 return WXVARIANT(*wxNORMAL_FONT);
1087 if ( valueType == wxS("wxPoint") )
1088 return WXVARIANT(wxPoint(0, 0));
1089 if ( valueType == wxS("wxSize") )
1090 return WXVARIANT(wxSize(0, 0));
1091 }
1092
1093 return wxVariant();
1094 }
1095
1096 void wxPGProperty::SetCell( int column, wxPGCell* cellObj )
1097 {
1098 if ( column >= (int)m_cells.size() )
1099 m_cells.SetCount(column+1, NULL);
1100
1101 delete (wxPGCell*) m_cells[column];
1102 m_cells[column] = cellObj;
1103 }
1104
1105 wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const
1106 {
1107 return NULL;
1108 }
1109
1110 bool wxPGProperty::DoSetAttribute( const wxString& WXUNUSED(name), wxVariant& WXUNUSED(value) )
1111 {
1112 return false;
1113 }
1114
1115 void wxPGProperty::SetAttribute( const wxString& name, wxVariant value )
1116 {
1117 if ( DoSetAttribute( name, value ) )
1118 {
1119 // Support working without grid, when possible
1120 if ( wxPGGlobalVars->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES ) )
1121 return;
1122 }
1123
1124 m_attributes.Set( name, value );
1125 }
1126
1127 void wxPGProperty::SetAttributes( const wxPGAttributeStorage& attributes )
1128 {
1129 wxPGAttributeStorage::const_iterator it = attributes.StartIteration();
1130 wxVariant variant;
1131
1132 while ( attributes.GetNext(it, variant) )
1133 SetAttribute( variant.GetName(), variant );
1134 }
1135
1136 wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
1137 {
1138 return wxVariant();
1139 }
1140
1141
1142 wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
1143 {
1144 return m_attributes.FindValue(name);
1145 }
1146
1147 wxString wxPGProperty::GetAttribute( const wxString& name, const wxString& defVal ) const
1148 {
1149 wxVariant variant = m_attributes.FindValue(name);
1150
1151 if ( !variant.IsNull() )
1152 return variant.GetString();
1153
1154 return defVal;
1155 }
1156
1157 long wxPGProperty::GetAttributeAsLong( const wxString& name, long defVal ) const
1158 {
1159 wxVariant variant = m_attributes.FindValue(name);
1160
1161 return wxPGVariantToInt(variant, defVal);
1162 }
1163
1164 double wxPGProperty::GetAttributeAsDouble( const wxString& name, double defVal ) const
1165 {
1166 double retVal;
1167 wxVariant variant = m_attributes.FindValue(name);
1168
1169 if ( wxPGVariantToDouble(variant, &retVal) )
1170 return retVal;
1171
1172 return defVal;
1173 }
1174
1175 wxVariant wxPGProperty::GetAttributesAsList() const
1176 {
1177 wxVariantList tempList;
1178 wxVariant v( tempList, wxString::Format(wxS("@%s@attr"),m_name.c_str()) );
1179
1180 wxPGAttributeStorage::const_iterator it = m_attributes.StartIteration();
1181 wxVariant variant;
1182
1183 while ( m_attributes.GetNext(it, variant) )
1184 v.Append(variant);
1185
1186 return v;
1187 }
1188
1189 // Slots of utility flags are NULL
1190 const unsigned int gs_propFlagToStringSize = 14;
1191
1192 static const wxChar* gs_propFlagToString[gs_propFlagToStringSize] = {
1193 NULL,
1194 wxT("DISABLED"),
1195 wxT("HIDDEN"),
1196 NULL,
1197 wxT("NOEDITOR"),
1198 wxT("COLLAPSED"),
1199 NULL,
1200 NULL,
1201 NULL,
1202 NULL,
1203 NULL,
1204 NULL,
1205 NULL,
1206 NULL
1207 };
1208
1209 wxString wxPGProperty::GetFlagsAsString( FlagType flagsMask ) const
1210 {
1211 wxString s;
1212 int relevantFlags = m_flags & flagsMask & wxPG_STRING_STORED_FLAGS;
1213 FlagType a = 1;
1214
1215 unsigned int i = 0;
1216 for ( i=0; i<gs_propFlagToStringSize; i++ )
1217 {
1218 if ( relevantFlags & a )
1219 {
1220 const wxChar* fs = gs_propFlagToString[i];
1221 wxASSERT(fs);
1222 if ( s.length() )
1223 s << wxS("|");
1224 s << fs;
1225 }
1226 a = a << 1;
1227 }
1228
1229 return s;
1230 }
1231
1232 void wxPGProperty::SetFlagsFromString( const wxString& str )
1233 {
1234 FlagType flags = 0;
1235
1236 WX_PG_TOKENIZER1_BEGIN(str, wxS('|'))
1237 unsigned int i;
1238 for ( i=0; i<gs_propFlagToStringSize; i++ )
1239 {
1240 const wxChar* fs = gs_propFlagToString[i];
1241 if ( fs && str == fs )
1242 {
1243 flags |= (1<<i);
1244 break;
1245 }
1246 }
1247 WX_PG_TOKENIZER1_END()
1248
1249 m_flags = (m_flags & ~wxPG_STRING_STORED_FLAGS) | flags;
1250 }
1251
1252 wxValidator* wxPGProperty::DoGetValidator() const
1253 {
1254 return (wxValidator*) NULL;
1255 }
1256
1257 int wxPGProperty::InsertChoice( const wxString& label, int index, int value )
1258 {
1259 wxPropertyGrid* pg = GetGrid();
1260 int sel = GetChoiceSelection();
1261
1262 int newSel = sel;
1263
1264 if ( index == wxNOT_FOUND )
1265 index = m_choices.GetCount();
1266
1267 if ( index <= sel )
1268 newSel++;
1269
1270 m_choices.Insert(label, index, value);
1271
1272 if ( sel != newSel )
1273 SetChoiceSelection(newSel);
1274
1275 if ( this == pg->GetSelection() )
1276 GetEditorClass()->InsertItem(pg->GetEditorControl(),label,index);
1277
1278 return index;
1279 }
1280
1281
1282 void wxPGProperty::DeleteChoice( int index )
1283 {
1284 wxPropertyGrid* pg = GetGrid();
1285
1286 int sel = GetChoiceSelection();
1287 int newSel = sel;
1288
1289 // Adjust current value
1290 if ( sel == index )
1291 {
1292 SetValueToUnspecified();
1293 newSel = 0;
1294 }
1295 else if ( index < sel )
1296 {
1297 newSel--;
1298 }
1299
1300 m_choices.RemoveAt(index);
1301
1302 if ( sel != newSel )
1303 SetChoiceSelection(newSel);
1304
1305 if ( this == pg->GetSelection() )
1306 GetEditorClass()->DeleteItem(pg->GetEditorControl(), index);
1307 }
1308
1309 int wxPGProperty::GetChoiceSelection() const
1310 {
1311 wxVariant value = GetValue();
1312 wxString valueType = value.GetType();
1313 int index = wxNOT_FOUND;
1314
1315 if ( IsValueUnspecified() || !m_choices.GetCount() )
1316 return wxNOT_FOUND;
1317
1318 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1319 {
1320 index = value.GetLong();
1321 }
1322 else if ( valueType == wxPG_VARIANT_TYPE_STRING )
1323 {
1324 index = m_choices.Index(value.GetString());
1325 }
1326 else if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1327 {
1328 index = value.GetBool()? 1 : 0;
1329 }
1330
1331 return index;
1332 }
1333
1334 void wxPGProperty::SetChoiceSelection( int newValue )
1335 {
1336 // Changes value of a property with choices, but only
1337 // works if the value type is long or string.
1338 wxString valueType = GetValue().GetType();
1339
1340 wxCHECK_RET( m_choices.IsOk(), wxT("invalid choiceinfo") );
1341
1342 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1343 {
1344 SetValue( m_choices.GetLabel(newValue) );
1345 }
1346 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1347 {
1348 SetValue( (long) newValue );
1349 }
1350 }
1351
1352 bool wxPGProperty::SetChoices( wxPGChoices& choices )
1353 {
1354 m_choices.Assign(choices);
1355
1356 {
1357 // This may be needed to trigger some initialization
1358 // (but don't do it if property is somewhat uninitialized)
1359 wxVariant defVal = GetDefaultValue();
1360 if ( defVal.IsNull() )
1361 return false;
1362
1363 SetValue(defVal);
1364 }
1365
1366 return true;
1367 }
1368
1369
1370 const wxPGEditor* wxPGProperty::GetEditorClass() const
1371 {
1372 const wxPGEditor* editor;
1373
1374 if ( !m_customEditor )
1375 {
1376 editor = DoGetEditorClass();
1377 }
1378 else
1379 editor = m_customEditor;
1380
1381 //
1382 // Maybe override editor if common value specified
1383 if ( GetDisplayedCommonValueCount() )
1384 {
1385 // TextCtrlAndButton -> ComboBoxAndButton
1386 if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor)) )
1387 editor = wxPG_EDITOR(ChoiceAndButton);
1388
1389 // TextCtrl -> ComboBox
1390 else if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlEditor)) )
1391 editor = wxPG_EDITOR(ComboBox);
1392 }
1393
1394 return editor;
1395 }
1396
1397 bool wxPGProperty::HasVisibleChildren() const
1398 {
1399 unsigned int i;
1400
1401 for ( i=0; i<GetChildCount(); i++ )
1402 {
1403 wxPGProperty* child = Item(i);
1404
1405 if ( !child->HasFlag(wxPG_PROP_HIDDEN) )
1406 return true;
1407 }
1408
1409 return false;
1410 }
1411
1412 bool wxPGProperty::PrepareValueForDialogEditing( wxPropertyGrid* propGrid )
1413 {
1414 return propGrid->EditorValidate();
1415 }
1416
1417
1418 bool wxPGProperty::RecreateEditor()
1419 {
1420 wxPropertyGrid* pg = GetGrid();
1421 wxASSERT(pg);
1422
1423 wxPGProperty* selected = pg->GetSelection();
1424 if ( this == selected )
1425 {
1426 pg->DoSelectProperty(this, wxPG_SEL_FORCE);
1427 return true;
1428 }
1429 return false;
1430 }
1431
1432
1433 void wxPGProperty::SetValueImage( wxBitmap& bmp )
1434 {
1435 delete m_valueBitmap;
1436
1437 if ( &bmp && bmp.Ok() )
1438 {
1439 // Resize the image
1440 wxSize maxSz = GetGrid()->GetImageSize();
1441 wxSize imSz(bmp.GetWidth(),bmp.GetHeight());
1442
1443 if ( imSz.x != maxSz.x || imSz.y != maxSz.y )
1444 {
1445 // Create a memory DC
1446 wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth());
1447
1448 wxMemoryDC dc;
1449 dc.SelectObject(*bmpNew);
1450
1451 // Scale
1452 // FIXME: This is ugly - use image or wait for scaling patch.
1453 double scaleX = (double)maxSz.x / (double)imSz.x;
1454 double scaleY = (double)maxSz.y / (double)imSz.y;
1455
1456 dc.SetUserScale(scaleX,scaleY);
1457
1458 dc.DrawBitmap( bmp, 0, 0 );
1459
1460 m_valueBitmap = bmpNew;
1461 }
1462 else
1463 {
1464 m_valueBitmap = new wxBitmap(bmp);
1465 }
1466
1467 m_flags |= wxPG_PROP_CUSTOMIMAGE;
1468 }
1469 else
1470 {
1471 m_valueBitmap = NULL;
1472 m_flags &= ~(wxPG_PROP_CUSTOMIMAGE);
1473 }
1474 }
1475
1476
1477 wxPGProperty* wxPGProperty::GetMainParent() const
1478 {
1479 const wxPGProperty* curChild = this;
1480 const wxPGProperty* curParent = m_parent;
1481
1482 while ( curParent && !curParent->IsCategory() )
1483 {
1484 curChild = curParent;
1485 curParent = curParent->m_parent;
1486 }
1487
1488 return (wxPGProperty*) curChild;
1489 }
1490
1491
1492 const wxPGProperty* wxPGProperty::GetLastVisibleSubItem() const
1493 {
1494 //
1495 // Returns last visible sub-item, recursively.
1496 if ( !IsExpanded() || !GetChildCount() )
1497 return this;
1498
1499 return Last()->GetLastVisibleSubItem();
1500 }
1501
1502
1503 bool wxPGProperty::IsVisible() const
1504 {
1505 const wxPGProperty* parent;
1506
1507 if ( HasFlag(wxPG_PROP_HIDDEN) )
1508 return false;
1509
1510 for ( parent = GetParent(); parent != NULL; parent = parent->GetParent() )
1511 {
1512 if ( !parent->IsExpanded() || parent->HasFlag(wxPG_PROP_HIDDEN) )
1513 return false;
1514 }
1515
1516 return true;
1517 }
1518
1519 wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const
1520 {
1521 wxPropertyGridPageState* state = GetParentState();
1522 wxPropertyGrid* propGrid = state->GetGrid();
1523 if ( state == propGrid->GetState() )
1524 return propGrid;
1525 return NULL;
1526 }
1527
1528
1529 int wxPGProperty::GetY2( int lh ) const
1530 {
1531 const wxPGProperty* parent;
1532 const wxPGProperty* child = this;
1533
1534 int y = 0;
1535
1536 for ( parent = GetParent(); parent != NULL; parent = child->GetParent() )
1537 {
1538 if ( !parent->IsExpanded() )
1539 return -1;
1540 y += parent->GetChildrenHeight(lh, child->GetIndexInParent());
1541 y += lh;
1542 child = parent;
1543 }
1544
1545 y -= lh; // need to reduce one level
1546
1547 return y;
1548 }
1549
1550
1551 int wxPGProperty::GetY() const
1552 {
1553 return GetY2(GetGrid()->GetRowHeight());
1554 }
1555
1556 // This is used by Insert etc.
1557 void wxPGProperty::AddChild2( wxPGProperty* prop, int index, bool correct_mode )
1558 {
1559 if ( index < 0 || (size_t)index >= m_children.GetCount() )
1560 {
1561 if ( correct_mode ) prop->m_arrIndex = m_children.GetCount();
1562 m_children.Add( prop );
1563 }
1564 else
1565 {
1566 m_children.Insert( prop, index );
1567 if ( correct_mode ) FixIndexesOfChildren( index );
1568 }
1569
1570 prop->m_parent = this;
1571 }
1572
1573 // This is used by properties that have fixed sub-properties
1574 void wxPGProperty::AddChild( wxPGProperty* prop )
1575 {
1576 wxASSERT_MSG( prop->GetBaseName().length(),
1577 "Property's children must have unique, non-empty names within their scope" );
1578
1579 prop->m_arrIndex = m_children.GetCount();
1580 m_children.Add( prop );
1581
1582 int custImgHeight = prop->OnMeasureImage().y;
1583 if ( custImgHeight < 0 /*|| custImgHeight > 1*/ )
1584 prop->m_flags |= wxPG_PROP_CUSTOMIMAGE;
1585
1586 prop->m_parent = this;
1587 }
1588
1589
1590 void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const
1591 {
1592 wxASSERT( GetChildCount() );
1593 wxASSERT( !IsCategory() );
1594
1595 *value = GetValue();
1596
1597 if ( !list.GetCount() )
1598 return;
1599
1600 wxASSERT( GetChildCount() >= (unsigned int)list.GetCount() );
1601
1602 bool allChildrenSpecified;
1603
1604 // Don't fully update aggregate properties unless all children have
1605 // specified value
1606 if ( HasFlag(wxPG_PROP_AGGREGATE) )
1607 allChildrenSpecified = AreAllChildrenSpecified(&list);
1608 else
1609 allChildrenSpecified = true;
1610
1611 wxVariant childValue = list[0];
1612 unsigned int i;
1613 unsigned int n = 0;
1614
1615 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
1616
1617 for ( i=0; i<GetChildCount(); i++ )
1618 {
1619 const wxPGProperty* child = Item(i);
1620
1621 if ( childValue.GetName() == child->GetBaseName() )
1622 {
1623 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
1624
1625 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1626 {
1627 wxVariant cv2(child->GetValue());
1628 child->AdaptListToValue(childValue, &cv2);
1629 childValue = cv2;
1630 }
1631
1632 if ( allChildrenSpecified )
1633 ChildChanged(*value, i, childValue);
1634 n++;
1635 if ( n == (unsigned int)list.GetCount() )
1636 break;
1637 childValue = list[n];
1638 }
1639 }
1640 }
1641
1642
1643 void wxPGProperty::FixIndexesOfChildren( size_t starthere )
1644 {
1645 size_t i;
1646 for ( i=starthere;i<GetChildCount();i++)
1647 Item(i)->m_arrIndex = i;
1648 }
1649
1650
1651 // Returns (direct) child property with given name (or NULL if not found)
1652 wxPGProperty* wxPGProperty::GetPropertyByName( const wxString& name ) const
1653 {
1654 size_t i;
1655
1656 for ( i=0; i<GetChildCount(); i++ )
1657 {
1658 wxPGProperty* p = Item(i);
1659 if ( p->m_name == name )
1660 return p;
1661 }
1662
1663 // Does it have point, then?
1664 int pos = name.Find(wxS('.'));
1665 if ( pos <= 0 )
1666 return (wxPGProperty*) NULL;
1667
1668 wxPGProperty* p = GetPropertyByName(name. substr(0,pos));
1669
1670 if ( !p || !p->GetChildCount() )
1671 return NULL;
1672
1673 return p->GetPropertyByName(name.substr(pos+1,name.length()-pos-1));
1674 }
1675
1676 wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const
1677 {
1678 unsigned int i = hintIndex;
1679
1680 if ( i >= GetChildCount() )
1681 i = 0;
1682
1683 unsigned int lastIndex = i - 1;
1684
1685 if ( lastIndex >= GetChildCount() )
1686 lastIndex = GetChildCount() - 1;
1687
1688 for (;;)
1689 {
1690 wxPGProperty* p = Item(i);
1691 if ( p->m_name == name )
1692 return p;
1693
1694 if ( i == lastIndex )
1695 break;
1696
1697 i++;
1698 if ( i == GetChildCount() )
1699 i = 0;
1700 };
1701
1702 return NULL;
1703 }
1704
1705 int wxPGProperty::GetChildrenHeight( int lh, int iMax_ ) const
1706 {
1707 // Returns height of children, recursively, and
1708 // by taking expanded/collapsed status into account.
1709 //
1710 // iMax is used when finding property y-positions.
1711 //
1712 unsigned int i = 0;
1713 int h = 0;
1714
1715 if ( iMax_ == -1 )
1716 iMax_ = GetChildCount();
1717
1718 unsigned int iMax = iMax_;
1719
1720 wxASSERT( iMax <= GetChildCount() );
1721
1722 if ( !IsExpanded() && GetParent() )
1723 return 0;
1724
1725 while ( i < iMax )
1726 {
1727 wxPGProperty* pwc = (wxPGProperty*) Item(i);
1728
1729 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
1730 {
1731 if ( !pwc->IsExpanded() ||
1732 pwc->GetChildCount() == 0 )
1733 h += lh;
1734 else
1735 h += pwc->GetChildrenHeight(lh) + lh;
1736 }
1737
1738 i++;
1739 }
1740
1741 return h;
1742 }
1743
1744 wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y, unsigned int lh, unsigned int* nextItemY ) const
1745 {
1746 wxASSERT( nextItemY );
1747
1748 // Linear search at the moment
1749 //
1750 // nextItemY = y of next visible property, final value will be written back.
1751 wxPGProperty* result = NULL;
1752 wxPGProperty* current = NULL;
1753 unsigned int iy = *nextItemY;
1754 unsigned int i = 0;
1755 unsigned int iMax = GetChildCount();
1756
1757 while ( i < iMax )
1758 {
1759 wxPGProperty* pwc = Item(i);
1760
1761 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
1762 {
1763 // Found?
1764 if ( y < iy )
1765 {
1766 result = current;
1767 break;
1768 }
1769
1770 iy += lh;
1771
1772 if ( pwc->IsExpanded() &&
1773 pwc->GetChildCount() > 0 )
1774 {
1775 result = (wxPGProperty*) pwc->GetItemAtY( y, lh, &iy );
1776 if ( result )
1777 break;
1778 }
1779
1780 current = pwc;
1781 }
1782
1783 i++;
1784 }
1785
1786 // Found?
1787 if ( !result && y < iy )
1788 result = current;
1789
1790 *nextItemY = iy;
1791
1792 /*
1793 if ( current )
1794 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
1795 else
1796 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
1797 */
1798
1799 return (wxPGProperty*) result;
1800 }
1801
1802 void wxPGProperty::Empty()
1803 {
1804 size_t i;
1805 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES) )
1806 {
1807 for ( i=0; i<GetChildCount(); i++ )
1808 {
1809 wxPGProperty* p = (wxPGProperty*) Item(i);
1810 delete p;
1811 }
1812 }
1813
1814 m_children.Empty();
1815 }
1816
1817 void wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
1818 int WXUNUSED(childIndex),
1819 wxVariant& WXUNUSED(childValue) ) const
1820 {
1821 }
1822
1823 bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const
1824 {
1825 unsigned int i;
1826
1827 const wxVariantList* pList = NULL;
1828 wxVariantList::const_iterator node;
1829
1830 if ( pendingList )
1831 {
1832 pList = &pendingList->GetList();
1833 node = pList->begin();
1834 }
1835
1836 for ( i=0; i<GetChildCount(); i++ )
1837 {
1838 wxPGProperty* child = Item(i);
1839 const wxVariant* listValue = NULL;
1840 wxVariant value;
1841
1842 if ( pendingList )
1843 {
1844 const wxString& childName = child->GetBaseName();
1845
1846 for ( ; node != pList->end(); node++ )
1847 {
1848 const wxVariant& item = *((const wxVariant*)*node);
1849 if ( item.GetName() == childName )
1850 {
1851 listValue = &item;
1852 value = item;
1853 break;
1854 }
1855 }
1856 }
1857
1858 if ( !listValue )
1859 value = child->GetValue();
1860
1861 if ( value.IsNull() )
1862 return false;
1863
1864 // Check recursively
1865 if ( child->GetChildCount() )
1866 {
1867 const wxVariant* childList = NULL;
1868
1869 if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST )
1870 childList = listValue;
1871
1872 if ( !child->AreAllChildrenSpecified((wxVariant*)childList) )
1873 return false;
1874 }
1875 }
1876
1877 return true;
1878 }
1879
1880 wxPGProperty* wxPGProperty::UpdateParentValues()
1881 {
1882 wxPGProperty* parent = m_parent;
1883 if ( parent && parent->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
1884 !parent->IsCategory() && !parent->IsRoot() )
1885 {
1886 wxString s;
1887 parent->GenerateComposedValue(s, 0);
1888 parent->m_value = s;
1889 return parent->UpdateParentValues();
1890 }
1891 return this;
1892 }
1893
1894 bool wxPGProperty::IsTextEditable() const
1895 {
1896 if ( HasFlag(wxPG_PROP_READONLY) )
1897 return false;
1898
1899 if ( HasFlag(wxPG_PROP_NOEDITOR) &&
1900 (GetChildCount() ||
1901 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
1902 )
1903 return false;
1904
1905 return true;
1906 }
1907
1908 // Call for after sub-properties added with AddChild
1909 void wxPGProperty::PrepareSubProperties()
1910 {
1911 wxPropertyGridPageState* state = GetParentState();
1912
1913 wxASSERT(state);
1914
1915 if ( !GetChildCount() )
1916 return;
1917
1918 wxByte depth = m_depth + 1;
1919 wxByte depthBgCol = m_depthBgCol;
1920
1921 FlagType inheritFlags = m_flags & wxPG_INHERITED_PROPFLAGS;
1922
1923 wxByte bgColIndex = m_bgColIndex;
1924 wxByte fgColIndex = m_fgColIndex;
1925
1926 //
1927 // Set some values to the children
1928 //
1929 size_t i = 0;
1930 wxPGProperty* nparent = this;
1931
1932 while ( i < nparent->GetChildCount() )
1933 {
1934 wxPGProperty* np = nparent->Item(i);
1935
1936 np->m_parentState = state;
1937 np->m_flags |= inheritFlags; // Hideable also if parent.
1938 np->m_depth = depth;
1939 np->m_depthBgCol = depthBgCol;
1940 np->m_bgColIndex = bgColIndex;
1941 np->m_fgColIndex = fgColIndex;
1942
1943 // Also handle children of children
1944 if ( np->GetChildCount() > 0 )
1945 {
1946 nparent = np;
1947 i = 0;
1948
1949 // Init
1950 nparent->SetParentalType(wxPG_PROP_AGGREGATE);
1951 nparent->SetExpanded(false);
1952 depth++;
1953 }
1954 else
1955 {
1956 // Next sibling
1957 i++;
1958 }
1959
1960 // After reaching last sibling, go back to processing
1961 // siblings of the parent
1962 while ( i >= nparent->GetChildCount() )
1963 {
1964 // Exit the loop when top parent hit
1965 if ( nparent == this )
1966 break;
1967
1968 depth--;
1969
1970 i = nparent->GetArrIndex() + 1;
1971 nparent = nparent->GetParent();
1972 }
1973 }
1974 }
1975
1976 // Call after fixed sub-properties added/removed after creation.
1977 // if oldSelInd >= 0 and < new max items, then selection is
1978 // moved to it. Note: oldSelInd -2 indicates that this property
1979 // should be selected.
1980 void wxPGProperty::SubPropsChanged( int oldSelInd )
1981 {
1982 wxPropertyGridPageState* state = GetParentState();
1983 wxPropertyGrid* grid = state->GetGrid();
1984
1985 PrepareSubProperties();
1986
1987 wxPGProperty* sel = (wxPGProperty*) NULL;
1988 if ( oldSelInd >= (int)m_children.GetCount() )
1989 oldSelInd = (int)m_children.GetCount() - 1;
1990
1991 if ( oldSelInd >= 0 )
1992 sel = (wxPGProperty*) m_children[oldSelInd];
1993 else if ( oldSelInd == -2 )
1994 sel = this;
1995
1996 if ( sel )
1997 state->DoSelectProperty(sel);
1998
1999 if ( state == grid->GetState() )
2000 {
2001 grid->GetPanel()->Refresh();
2002 }
2003 }
2004
2005 // -----------------------------------------------------------------------
2006 // wxPGRootProperty
2007 // -----------------------------------------------------------------------
2008
2009 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2010 IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2011
2012
2013 wxPGRootProperty::wxPGRootProperty()
2014 : wxPGProperty()
2015 {
2016 #ifdef __WXDEBUG__
2017 m_name = wxS("<root>");
2018 #endif
2019 SetParentalType(0);
2020 m_depth = 0;
2021 }
2022
2023
2024 wxPGRootProperty::~wxPGRootProperty()
2025 {
2026 }
2027
2028
2029 // -----------------------------------------------------------------------
2030 // wxPropertyCategory
2031 // -----------------------------------------------------------------------
2032
2033 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2034 IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2035
2036 void wxPropertyCategory::Init()
2037 {
2038 // don't set colour - prepareadditem method should do this
2039 SetParentalType(wxPG_PROP_CATEGORY);
2040 m_capFgColIndex = 1;
2041 m_textExtent = -1;
2042 }
2043
2044 wxPropertyCategory::wxPropertyCategory()
2045 : wxPGProperty()
2046 {
2047 Init();
2048 }
2049
2050
2051 wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2052 : wxPGProperty(label,name)
2053 {
2054 Init();
2055 }
2056
2057
2058 wxPropertyCategory::~wxPropertyCategory()
2059 {
2060 }
2061
2062
2063 wxString wxPropertyCategory::GetValueAsString( int ) const
2064 {
2065 return wxEmptyString;
2066 }
2067
2068 int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const
2069 {
2070 if ( m_textExtent > 0 )
2071 return m_textExtent;
2072 int x = 0, y = 0;
2073 ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2074 return x;
2075 }
2076
2077 void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font )
2078 {
2079 int x = 0, y = 0;
2080 wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2081 m_textExtent = x;
2082 }
2083
2084 // -----------------------------------------------------------------------
2085 // wxPGAttributeStorage
2086 // -----------------------------------------------------------------------
2087
2088 wxPGAttributeStorage::wxPGAttributeStorage()
2089 {
2090 }
2091
2092 wxPGAttributeStorage::~wxPGAttributeStorage()
2093 {
2094 wxPGHashMapS2P::iterator it;
2095
2096 for ( it = m_map.begin(); it != m_map.end(); it++ )
2097 {
2098 wxVariantData* data = (wxVariantData*) it->second;
2099 data->DecRef();
2100 }
2101 }
2102
2103 void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value )
2104 {
2105 wxVariantData* data = value.GetData();
2106
2107 // Free old, if any
2108 wxPGHashMapS2P::iterator it = m_map.find(name);
2109 if ( it != m_map.end() )
2110 ((wxVariantData*)it->second)->DecRef();
2111
2112 if ( data )
2113 data->IncRef();
2114
2115 m_map[name] = data;
2116 }
2117
2118 #endif // wxUSE_PROPGRID