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