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