]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/propgrid/property.cpp
disabling multiline text controls correctly
[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 // Create a memory DC
2101 wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth());
2102
2103 wxMemoryDC dc;
2104 dc.SelectObject(*bmpNew);
2105
2106 // Scale
2107 // FIXME: This is ugly - use image or wait for scaling patch.
2108 double scaleY = (double)maxSz.y / (double)imSz.y;
2109
2110 dc.SetUserScale(scaleY, scaleY);
2111
2112 dc.DrawBitmap(bmp, 0, 0);
2113
2114 m_valueBitmap = bmpNew;
2115 }
2116 else
2117 {
2118 m_valueBitmap = new wxBitmap(bmp);
2119 }
2120
2121 m_flags |= wxPG_PROP_CUSTOMIMAGE;
2122 }
2123 else
2124 {
2125 m_valueBitmap = NULL;
2126 m_flags &= ~(wxPG_PROP_CUSTOMIMAGE);
2127 }
2128}
2129
2130
2131wxPGProperty* wxPGProperty::GetMainParent() const
2132{
2133 const wxPGProperty* curChild = this;
2134 const wxPGProperty* curParent = m_parent;
2135
2136 while ( curParent && !curParent->IsCategory() )
2137 {
2138 curChild = curParent;
2139 curParent = curParent->m_parent;
2140 }
2141
2142 return (wxPGProperty*) curChild;
2143}
2144
2145
2146const wxPGProperty* wxPGProperty::GetLastVisibleSubItem() const
2147{
2148 //
2149 // Returns last visible sub-item, recursively.
2150 if ( !IsExpanded() || !GetChildCount() )
2151 return this;
2152
2153 return Last()->GetLastVisibleSubItem();
2154}
2155
2156
2157bool wxPGProperty::IsVisible() const
2158{
2159 const wxPGProperty* parent;
2160
2161 if ( HasFlag(wxPG_PROP_HIDDEN) )
2162 return false;
2163
2164 for ( parent = GetParent(); parent != NULL; parent = parent->GetParent() )
2165 {
2166 if ( !parent->IsExpanded() || parent->HasFlag(wxPG_PROP_HIDDEN) )
2167 return false;
2168 }
2169
2170 return true;
2171}
2172
2173wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const
2174{
2175 wxPropertyGridPageState* state = GetParentState();
2176 if ( !state )
2177 return NULL;
2178 wxPropertyGrid* propGrid = state->GetGrid();
2179 if ( state == propGrid->GetState() )
2180 return propGrid;
2181 return NULL;
2182}
2183
2184
2185int wxPGProperty::GetY2( int lh ) const
2186{
2187 const wxPGProperty* parent;
2188 const wxPGProperty* child = this;
2189
2190 int y = 0;
2191
2192 for ( parent = GetParent(); parent != NULL; parent = child->GetParent() )
2193 {
2194 if ( !parent->IsExpanded() )
2195 return -1;
2196 y += parent->GetChildrenHeight(lh, child->GetIndexInParent());
2197 y += lh;
2198 child = parent;
2199 }
2200
2201 y -= lh; // need to reduce one level
2202
2203 return y;
2204}
2205
2206
2207int wxPGProperty::GetY() const
2208{
2209 return GetY2(GetGrid()->GetRowHeight());
2210}
2211
2212// This is used by Insert etc.
2213void wxPGProperty::DoAddChild( wxPGProperty* prop, int index,
2214 bool correct_mode )
2215{
2216 if ( index < 0 || (size_t)index >= m_children.size() )
2217 {
2218 if ( correct_mode ) prop->m_arrIndex = m_children.size();
2219 m_children.push_back( prop );
2220 }
2221 else
2222 {
2223 m_children.insert( m_children.begin()+index, prop);
2224 if ( correct_mode ) FixIndicesOfChildren( index );
2225 }
2226
2227 prop->m_parent = this;
2228}
2229
2230void wxPGProperty::DoPreAddChild( int index, wxPGProperty* prop )
2231{
2232 wxASSERT_MSG( prop->GetBaseName().length(),
2233 "Property's children must have unique, non-empty "
2234 "names within their scope" );
2235
2236 prop->m_arrIndex = index;
2237 m_children.insert( m_children.begin()+index,
2238 prop );
2239
2240 int custImgHeight = prop->OnMeasureImage().y;
2241 if ( custImgHeight < 0 /*|| custImgHeight > 1*/ )
2242 prop->m_flags |= wxPG_PROP_CUSTOMIMAGE;
2243
2244 prop->m_parent = this;
2245}
2246
2247void wxPGProperty::AddPrivateChild( wxPGProperty* prop )
2248{
2249 if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) )
2250 SetParentalType(wxPG_PROP_AGGREGATE);
2251
2252 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
2253 wxPG_PROP_AGGREGATE,
2254 "Do not mix up AddPrivateChild() calls with other "
2255 "property adders." );
2256
2257 DoPreAddChild( m_children.size(), prop );
2258}
2259
2260#if wxPG_COMPATIBILITY_1_4
2261void wxPGProperty::AddChild( wxPGProperty* prop )
2262{
2263 AddPrivateChild(prop);
2264}
2265#endif
2266
2267wxPGProperty* wxPGProperty::InsertChild( int index,
2268 wxPGProperty* childProperty )
2269{
2270 if ( index < 0 )
2271 index = m_children.size();
2272
2273 if ( m_parentState )
2274 {
2275 m_parentState->DoInsert(this, index, childProperty);
2276 }
2277 else
2278 {
2279 if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) )
2280 SetParentalType(wxPG_PROP_MISC_PARENT);
2281
2282 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) ==
2283 wxPG_PROP_MISC_PARENT,
2284 "Do not mix up AddPrivateChild() calls with other "
2285 "property adders." );
2286
2287 DoPreAddChild( index, childProperty );
2288 }
2289
2290 return childProperty;
2291}
2292
2293void wxPGProperty::RemoveChild( wxPGProperty* p )
2294{
2295 wxArrayPGProperty::iterator it;
2296 wxArrayPGProperty& children = m_children;
2297
2298 for ( it=children.begin(); it != children.end(); it++ )
2299 {
2300 if ( *it == p )
2301 {
2302 children.erase(it);
2303 break;
2304 }
2305 }
2306}
2307
2308void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const
2309{
2310 wxASSERT( GetChildCount() );
2311 wxASSERT( !IsCategory() );
2312
2313 *value = GetValue();
2314
2315 if ( !list.GetCount() )
2316 return;
2317
2318 wxASSERT( GetChildCount() >= (unsigned int)list.GetCount() );
2319
2320 bool allChildrenSpecified;
2321
2322 // Don't fully update aggregate properties unless all children have
2323 // specified value
2324 if ( HasFlag(wxPG_PROP_AGGREGATE) )
2325 allChildrenSpecified = AreAllChildrenSpecified(&list);
2326 else
2327 allChildrenSpecified = true;
2328
2329 unsigned int i;
2330 unsigned int n = 0;
2331 wxVariant childValue = list[n];
2332
2333 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
2334
2335 for ( i=0; i<GetChildCount(); i++ )
2336 {
2337 const wxPGProperty* child = Item(i);
2338
2339 if ( childValue.GetName() == child->GetBaseName() )
2340 {
2341 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2342
2343 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
2344 {
2345 wxVariant cv2(child->GetValue());
2346 child->AdaptListToValue(childValue, &cv2);
2347 childValue = cv2;
2348 }
2349
2350 if ( allChildrenSpecified )
2351 {
2352 *value = ChildChanged(*value, i, childValue);
2353 }
2354
2355 n++;
2356 if ( n == (unsigned int)list.GetCount() )
2357 break;
2358 childValue = list[n];
2359 }
2360 }
2361}
2362
2363
2364void wxPGProperty::FixIndicesOfChildren( unsigned int starthere )
2365{
2366 size_t i;
2367 for ( i=starthere;i<GetChildCount();i++)
2368 Item(i)->m_arrIndex = i;
2369}
2370
2371
2372// Returns (direct) child property with given name (or NULL if not found)
2373wxPGProperty* wxPGProperty::GetPropertyByName( const wxString& name ) const
2374{
2375 size_t i;
2376
2377 for ( i=0; i<GetChildCount(); i++ )
2378 {
2379 wxPGProperty* p = Item(i);
2380 if ( p->m_name == name )
2381 return p;
2382 }
2383
2384 // Does it have point, then?
2385 int pos = name.Find(wxS('.'));
2386 if ( pos <= 0 )
2387 return NULL;
2388
2389 wxPGProperty* p = GetPropertyByName(name. substr(0,pos));
2390
2391 if ( !p || !p->GetChildCount() )
2392 return NULL;
2393
2394 return p->GetPropertyByName(name.substr(pos+1,name.length()-pos-1));
2395}
2396
2397wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const
2398{
2399 unsigned int i = hintIndex;
2400
2401 if ( i >= GetChildCount() )
2402 i = 0;
2403
2404 unsigned int lastIndex = i - 1;
2405
2406 if ( lastIndex >= GetChildCount() )
2407 lastIndex = GetChildCount() - 1;
2408
2409 for (;;)
2410 {
2411 wxPGProperty* p = Item(i);
2412 if ( p->m_name == name )
2413 return p;
2414
2415 if ( i == lastIndex )
2416 break;
2417
2418 i++;
2419 if ( i == GetChildCount() )
2420 i = 0;
2421 };
2422
2423 return NULL;
2424}
2425
2426int wxPGProperty::GetChildrenHeight( int lh, int iMax_ ) const
2427{
2428 // Returns height of children, recursively, and
2429 // by taking expanded/collapsed status into account.
2430 //
2431 // iMax is used when finding property y-positions.
2432 //
2433 unsigned int i = 0;
2434 int h = 0;
2435
2436 if ( iMax_ == -1 )
2437 iMax_ = GetChildCount();
2438
2439 unsigned int iMax = iMax_;
2440
2441 wxASSERT( iMax <= GetChildCount() );
2442
2443 if ( !IsExpanded() && GetParent() )
2444 return 0;
2445
2446 while ( i < iMax )
2447 {
2448 wxPGProperty* pwc = (wxPGProperty*) Item(i);
2449
2450 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2451 {
2452 if ( !pwc->IsExpanded() ||
2453 pwc->GetChildCount() == 0 )
2454 h += lh;
2455 else
2456 h += pwc->GetChildrenHeight(lh) + lh;
2457 }
2458
2459 i++;
2460 }
2461
2462 return h;
2463}
2464
2465wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y,
2466 unsigned int lh,
2467 unsigned int* nextItemY ) const
2468{
2469 wxASSERT( nextItemY );
2470
2471 // Linear search at the moment
2472 //
2473 // nextItemY = y of next visible property, final value will be written back.
2474 wxPGProperty* result = NULL;
2475 wxPGProperty* current = NULL;
2476 unsigned int iy = *nextItemY;
2477 unsigned int i = 0;
2478 unsigned int iMax = GetChildCount();
2479
2480 while ( i < iMax )
2481 {
2482 wxPGProperty* pwc = Item(i);
2483
2484 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2485 {
2486 // Found?
2487 if ( y < iy )
2488 {
2489 result = current;
2490 break;
2491 }
2492
2493 iy += lh;
2494
2495 if ( pwc->IsExpanded() &&
2496 pwc->GetChildCount() > 0 )
2497 {
2498 result = (wxPGProperty*) pwc->GetItemAtY( y, lh, &iy );
2499 if ( result )
2500 break;
2501 }
2502
2503 current = pwc;
2504 }
2505
2506 i++;
2507 }
2508
2509 // Found?
2510 if ( !result && y < iy )
2511 result = current;
2512
2513 *nextItemY = iy;
2514
2515 /*
2516 if ( current )
2517 {
2518 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
2519 }
2520 else
2521 {
2522 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
2523 }
2524 */
2525
2526 return (wxPGProperty*) result;
2527}
2528
2529void wxPGProperty::Empty()
2530{
2531 size_t i;
2532 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES) )
2533 {
2534 for ( i=0; i<GetChildCount(); i++ )
2535 {
2536 delete m_children[i];
2537 }
2538 }
2539
2540 m_children.clear();
2541}
2542
2543wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y ) const
2544{
2545 unsigned int nextItem;
2546 return GetItemAtY( y, GetGrid()->GetRowHeight(), &nextItem);
2547}
2548
2549void wxPGProperty::DeleteChildren()
2550{
2551 wxPropertyGridPageState* state = m_parentState;
2552
2553 if ( !GetChildCount() )
2554 return;
2555
2556 // Because deletion is sometimes deferred, we have to use
2557 // this sort of code for enumerating the child properties.
2558 unsigned int i = GetChildCount();
2559 while ( i > 0 )
2560 {
2561 i--;
2562 state->DoDelete(Item(i), true);
2563 }
2564}
2565
2566wxVariant wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
2567 int WXUNUSED(childIndex),
2568 wxVariant& WXUNUSED(childValue) ) const
2569{
2570 return wxNullVariant;
2571}
2572
2573bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const
2574{
2575 unsigned int i;
2576
2577 const wxVariantList* pList = NULL;
2578 wxVariantList::const_iterator node;
2579
2580 if ( pendingList )
2581 {
2582 pList = &pendingList->GetList();
2583 node = pList->begin();
2584 }
2585
2586 for ( i=0; i<GetChildCount(); i++ )
2587 {
2588 wxPGProperty* child = Item(i);
2589 const wxVariant* listValue = NULL;
2590 wxVariant value;
2591
2592 if ( pendingList )
2593 {
2594 const wxString& childName = child->GetBaseName();
2595
2596 for ( ; node != pList->end(); ++node )
2597 {
2598 const wxVariant& item = *((const wxVariant*)*node);
2599 if ( item.GetName() == childName )
2600 {
2601 listValue = &item;
2602 value = item;
2603 break;
2604 }
2605 }
2606 }
2607
2608 if ( !listValue )
2609 value = child->GetValue();
2610
2611 if ( value.IsNull() )
2612 return false;
2613
2614 // Check recursively
2615 if ( child->GetChildCount() )
2616 {
2617 const wxVariant* childList = NULL;
2618
2619 if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST )
2620 childList = listValue;
2621
2622 if ( !child->AreAllChildrenSpecified((wxVariant*)childList) )
2623 return false;
2624 }
2625 }
2626
2627 return true;
2628}
2629
2630wxPGProperty* wxPGProperty::UpdateParentValues()
2631{
2632 wxPGProperty* parent = m_parent;
2633 if ( parent && parent->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
2634 !parent->IsCategory() && !parent->IsRoot() )
2635 {
2636 wxString s;
2637 parent->DoGenerateComposedValue(s);
2638 parent->m_value = s;
2639 return parent->UpdateParentValues();
2640 }
2641 return this;
2642}
2643
2644bool wxPGProperty::IsTextEditable() const
2645{
2646 if ( HasFlag(wxPG_PROP_READONLY) )
2647 return false;
2648
2649 if ( HasFlag(wxPG_PROP_NOEDITOR) &&
2650 (GetChildCount() ||
2651 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2652 )
2653 return false;
2654
2655 return true;
2656}
2657
2658// Call after fixed sub-properties added/removed after creation.
2659// if oldSelInd >= 0 and < new max items, then selection is
2660// moved to it. Note: oldSelInd -2 indicates that this property
2661// should be selected.
2662void wxPGProperty::SubPropsChanged( int oldSelInd )
2663{
2664 wxPropertyGridPageState* state = GetParentState();
2665 wxPropertyGrid* grid = state->GetGrid();
2666
2667 //
2668 // Re-repare children (recursively)
2669 for ( unsigned int i=0; i<GetChildCount(); i++ )
2670 {
2671 wxPGProperty* child = Item(i);
2672 child->InitAfterAdded(state, grid);
2673 }
2674
2675 wxPGProperty* sel = NULL;
2676 if ( oldSelInd >= (int)m_children.size() )
2677 oldSelInd = (int)m_children.size() - 1;
2678
2679 if ( oldSelInd >= 0 )
2680 sel = m_children[oldSelInd];
2681 else if ( oldSelInd == -2 )
2682 sel = this;
2683
2684 if ( sel )
2685 state->DoSelectProperty(sel);
2686
2687 if ( state == grid->GetState() )
2688 {
2689 grid->GetPanel()->Refresh();
2690 }
2691}
2692
2693// -----------------------------------------------------------------------
2694// wxPGRootProperty
2695// -----------------------------------------------------------------------
2696
2697WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2698IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2699
2700
2701wxPGRootProperty::wxPGRootProperty( const wxString& name )
2702 : wxPGProperty()
2703{
2704 m_name = name;
2705 m_label = m_name;
2706 SetParentalType(0);
2707 m_depth = 0;
2708}
2709
2710
2711wxPGRootProperty::~wxPGRootProperty()
2712{
2713}
2714
2715
2716// -----------------------------------------------------------------------
2717// wxPropertyCategory
2718// -----------------------------------------------------------------------
2719
2720WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2721IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2722
2723void wxPropertyCategory::Init()
2724{
2725 // don't set colour - prepareadditem method should do this
2726 SetParentalType(wxPG_PROP_CATEGORY);
2727 m_capFgColIndex = 1;
2728 m_textExtent = -1;
2729}
2730
2731wxPropertyCategory::wxPropertyCategory()
2732 : wxPGProperty()
2733{
2734 Init();
2735}
2736
2737
2738wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2739 : wxPGProperty(label,name)
2740{
2741 Init();
2742}
2743
2744
2745wxPropertyCategory::~wxPropertyCategory()
2746{
2747}
2748
2749
2750wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value),
2751 int WXUNUSED(argFlags) ) const
2752{
2753 if ( m_value.GetType() == wxPG_VARIANT_TYPE_STRING )
2754 return m_value.GetString();
2755 return wxEmptyString;
2756}
2757
2758wxString wxPropertyCategory::GetValueAsString( int argFlags ) const
2759{
2760#if wxPG_COMPATIBILITY_1_4
2761 // This is backwards compatibility test
2762 // That is, to make sure this function is not overridden
2763 // (instead, ValueToString() should be).
2764 if ( argFlags == 0xFFFF )
2765 {
2766 // Do not override! (for backwards compliancy)
2767 return g_invalidStringContent;
2768 }
2769#endif
2770
2771 // Unspecified value is always empty string
2772 if ( IsValueUnspecified() )
2773 return wxEmptyString;
2774
2775 return wxPGProperty::GetValueAsString(argFlags);
2776}
2777
2778int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const
2779{
2780 if ( m_textExtent > 0 )
2781 return m_textExtent;
2782 int x = 0, y = 0;
2783 ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2784 return x;
2785}
2786
2787void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font )
2788{
2789 int x = 0, y = 0;
2790 wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2791 m_textExtent = x;
2792}
2793
2794// -----------------------------------------------------------------------
2795// wxPGChoices
2796// -----------------------------------------------------------------------
2797
2798wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, int value )
2799{
2800 AllocExclusive();
2801
2802 wxPGChoiceEntry entry(label, value);
2803 return m_data->Insert( -1, entry );
2804}
2805
2806// -----------------------------------------------------------------------
2807
2808wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, const wxBitmap& bitmap, int value )
2809{
2810 AllocExclusive();
2811
2812 wxPGChoiceEntry entry(label, value);
2813 entry.SetBitmap(bitmap);
2814 return m_data->Insert( -1, entry );
2815}
2816
2817// -----------------------------------------------------------------------
2818
2819wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index )
2820{
2821 AllocExclusive();
2822
2823 return m_data->Insert( index, entry );
2824}
2825
2826// -----------------------------------------------------------------------
2827
2828wxPGChoiceEntry& wxPGChoices::Insert( const wxString& label, int index, int value )
2829{
2830 AllocExclusive();
2831
2832 wxPGChoiceEntry entry(label, value);
2833 return m_data->Insert( index, entry );
2834}
2835
2836// -----------------------------------------------------------------------
2837
2838wxPGChoiceEntry& wxPGChoices::AddAsSorted( const wxString& label, int value )
2839{
2840 AllocExclusive();
2841
2842 size_t index = 0;
2843
2844 while ( index < GetCount() )
2845 {
2846 int cmpRes = GetLabel(index).Cmp(label);
2847 if ( cmpRes > 0 )
2848 break;
2849 index++;
2850 }
2851
2852 wxPGChoiceEntry entry(label, value);
2853 return m_data->Insert( index, entry );
2854}
2855
2856// -----------------------------------------------------------------------
2857
2858void wxPGChoices::Add( const wxChar* const* labels, const ValArrItem* values )
2859{
2860 AllocExclusive();
2861
2862 unsigned int itemcount = 0;
2863 const wxChar* const* p = &labels[0];
2864 while ( *p ) { p++; itemcount++; }
2865
2866 unsigned int i;
2867 for ( i = 0; i < itemcount; i++ )
2868 {
2869 int value = i;
2870 if ( values )
2871 value = values[i];
2872 wxPGChoiceEntry entry(labels[i], value);
2873 m_data->Insert( i, entry );
2874 }
2875}
2876
2877// -----------------------------------------------------------------------
2878
2879void wxPGChoices::Add( const wxArrayString& arr, const wxArrayInt& arrint )
2880{
2881 AllocExclusive();
2882
2883 unsigned int i;
2884 unsigned int itemcount = arr.size();
2885
2886 for ( i = 0; i < itemcount; i++ )
2887 {
2888 int value = i;
2889 if ( &arrint && arrint.size() )
2890 value = arrint[i];
2891 wxPGChoiceEntry entry(arr[i], value);
2892 m_data->Insert( i, entry );
2893 }
2894}
2895
2896// -----------------------------------------------------------------------
2897
2898void wxPGChoices::RemoveAt(size_t nIndex, size_t count)
2899{
2900 AllocExclusive();
2901
2902 wxASSERT( m_data->GetRefCount() != -1 );
2903 m_data->m_items.erase(m_data->m_items.begin()+nIndex,
2904 m_data->m_items.begin()+nIndex+count);
2905}
2906
2907// -----------------------------------------------------------------------
2908
2909void wxPGChoices::Clear()
2910{
2911 if ( m_data != wxPGChoicesEmptyData )
2912 {
2913 AllocExclusive();
2914 m_data->Clear();
2915 }
2916}
2917
2918// -----------------------------------------------------------------------
2919
2920int wxPGChoices::Index( const wxString& str ) const
2921{
2922 if ( IsOk() )
2923 {
2924 unsigned int i;
2925 for ( i=0; i< m_data->GetCount(); i++ )
2926 {
2927 const wxPGChoiceEntry& entry = m_data->Item(i);
2928 if ( entry.HasText() && entry.GetText() == str )
2929 return i;
2930 }
2931 }
2932 return -1;
2933}
2934
2935// -----------------------------------------------------------------------
2936
2937int wxPGChoices::Index( int val ) const
2938{
2939 if ( IsOk() )
2940 {
2941 unsigned int i;
2942 for ( i=0; i< m_data->GetCount(); i++ )
2943 {
2944 const wxPGChoiceEntry& entry = m_data->Item(i);
2945 if ( entry.GetValue() == val )
2946 return i;
2947 }
2948 }
2949 return -1;
2950}
2951
2952// -----------------------------------------------------------------------
2953
2954wxArrayString wxPGChoices::GetLabels() const
2955{
2956 wxArrayString arr;
2957 unsigned int i;
2958
2959 if ( this && IsOk() )
2960 for ( i=0; i<GetCount(); i++ )
2961 arr.push_back(GetLabel(i));
2962
2963 return arr;
2964}
2965
2966// -----------------------------------------------------------------------
2967
2968wxArrayInt wxPGChoices::GetValuesForStrings( const wxArrayString& strings ) const
2969{
2970 wxArrayInt arr;
2971
2972 if ( IsOk() )
2973 {
2974 unsigned int i;
2975 for ( i=0; i< strings.size(); i++ )
2976 {
2977 int index = Index(strings[i]);
2978 if ( index >= 0 )
2979 arr.Add(GetValue(index));
2980 else
2981 arr.Add(wxPG_INVALID_VALUE);
2982 }
2983 }
2984
2985 return arr;
2986}
2987
2988// -----------------------------------------------------------------------
2989
2990wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings,
2991 wxArrayString* unmatched ) const
2992{
2993 wxArrayInt arr;
2994
2995 if ( IsOk() )
2996 {
2997 unsigned int i;
2998 for ( i=0; i< strings.size(); i++ )
2999 {
3000 const wxString& str = strings[i];
3001 int index = Index(str);
3002 if ( index >= 0 )
3003 arr.Add(index);
3004 else if ( unmatched )
3005 unmatched->Add(str);
3006 }
3007 }
3008
3009 return arr;
3010}
3011
3012// -----------------------------------------------------------------------
3013
3014void wxPGChoices::AllocExclusive()
3015{
3016 EnsureData();
3017
3018 if ( m_data->GetRefCount() != 1 )
3019 {
3020 wxPGChoicesData* data = new wxPGChoicesData();
3021 data->CopyDataFrom(m_data);
3022 Free();
3023 m_data = data;
3024 }
3025}
3026
3027// -----------------------------------------------------------------------
3028
3029void wxPGChoices::AssignData( wxPGChoicesData* data )
3030{
3031 Free();
3032
3033 if ( data != wxPGChoicesEmptyData )
3034 {
3035 m_data = data;
3036 data->IncRef();
3037 }
3038}
3039
3040// -----------------------------------------------------------------------
3041
3042void wxPGChoices::Init()
3043{
3044 m_data = wxPGChoicesEmptyData;
3045}
3046
3047// -----------------------------------------------------------------------
3048
3049void wxPGChoices::Free()
3050{
3051 if ( m_data != wxPGChoicesEmptyData )
3052 {
3053 m_data->DecRef();
3054 m_data = wxPGChoicesEmptyData;
3055 }
3056}
3057
3058// -----------------------------------------------------------------------
3059// wxPGAttributeStorage
3060// -----------------------------------------------------------------------
3061
3062wxPGAttributeStorage::wxPGAttributeStorage()
3063{
3064}
3065
3066wxPGAttributeStorage::~wxPGAttributeStorage()
3067{
3068 wxPGHashMapS2P::iterator it;
3069
3070 for ( it = m_map.begin(); it != m_map.end(); ++it )
3071 {
3072 wxVariantData* data = (wxVariantData*) it->second;
3073 data->DecRef();
3074 }
3075}
3076
3077void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value )
3078{
3079 wxVariantData* data = value.GetData();
3080
3081 // Free old, if any
3082 wxPGHashMapS2P::iterator it = m_map.find(name);
3083 if ( it != m_map.end() )
3084 {
3085 ((wxVariantData*)it->second)->DecRef();
3086
3087 if ( !data )
3088 {
3089 // If Null variant, just remove from set
3090 m_map.erase(it);
3091 return;
3092 }
3093 }
3094
3095 if ( data )
3096 {
3097 data->IncRef();
3098
3099 m_map[name] = data;
3100 }
3101}
3102
3103#endif // wxUSE_PROPGRID