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