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