]> git.saurik.com Git - wxWidgets.git/blame - src/propgrid/property.cpp
Eliminate need to call Connect() in wxPGEditor::CreateControls()
[wxWidgets.git] / src / propgrid / property.cpp
CommitLineData
1c4293cb
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/propgrid/property.cpp
3// Purpose: wxPGProperty and related support classes
4// Author: Jaakko Salli
5// Modified by:
6// Created: 2008-08-23
ea5af9c5 7// RCS-ID: $Id$
1c4293cb
VZ
8// Copyright: (c) Jaakko Salli
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx/wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
f4bc1aa2
JS
19#if wxUSE_PROPGRID
20
1c4293cb
VZ
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"
1c4293cb
VZ
32 #include "wx/pen.h"
33 #include "wx/brush.h"
1c4293cb 34 #include "wx/settings.h"
1c4293cb 35 #include "wx/intl.h"
1c4293cb
VZ
36#endif
37
3b211af1 38#include "wx/propgrid/propgrid.h"
1c4293cb
VZ
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
1425eca5
JS
46#if wxPG_COMPATIBILITY_1_4
47
48// Used to establish backwards compatiblity
49const char* g_invalidStringContent = "@__TOTALLY_INVALID_STRING__@";
50
51#endif
1c4293cb
VZ
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 if ( xOffset )
98 xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
99 dc.DrawText( text,
100 rect.x+xOffset+wxPG_XBEFORETEXT,
101 rect.y+((rect.height-dc.GetCharHeight())/2) );
102}
103
104void wxPGCellRenderer::DrawEditorValue( wxDC& dc, const wxRect& rect,
105 int xOffset, const wxString& text,
106 wxPGProperty* property,
107 const wxPGEditor* editor ) const
108{
109 if ( xOffset )
110 xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
111
112 int yOffset = ((rect.height-dc.GetCharHeight())/2);
113
114 if ( editor )
115 {
116 wxRect rect2(rect);
117 rect2.x += xOffset;
118 rect2.y += yOffset;
119 rect2.height -= yOffset;
120 editor->DrawValue( dc, rect2, property, text );
121 }
122 else
123 {
124 dc.DrawText( text,
125 rect.x+xOffset+wxPG_XBEFORETEXT,
126 rect.y+yOffset );
127 }
128}
129
130void wxPGCellRenderer::DrawCaptionSelectionRect( wxDC& dc, int x, int y, int w, int h ) const
131{
132 wxRect focusRect(x,y+((h-dc.GetCharHeight())/2),w,h);
133 wxPGDrawFocusRect(dc,focusRect);
134}
135
136int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& cell, int flags ) const
137{
138 int imageOffset = 0;
139
d7e2b522
JS
140 // If possible, use cell colours
141 if ( !(flags & DontUseCellBgCol) )
1c4293cb 142 {
d7e2b522
JS
143 dc.SetPen(cell.GetBgCol());
144 dc.SetBrush(cell.GetBgCol());
145 }
1c4293cb 146
d7e2b522
JS
147 if ( !(flags & DontUseCellFgCol) )
148 {
149 dc.SetTextForeground(cell.GetFgCol());
1c4293cb
VZ
150 }
151
d7e2b522
JS
152 // Draw Background
153 dc.DrawRectangle(rect);
154
1c4293cb
VZ
155 const wxBitmap& bmp = cell.GetBitmap();
156 if ( bmp.Ok() &&
d7e2b522
JS
157 // Do not draw oversized bitmap outside choice popup
158 ((flags & ChoicePopup) || bmp.GetHeight() < rect.height )
1c4293cb
VZ
159 )
160 {
161 dc.DrawBitmap( bmp,
162 rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
163 rect.y + wxPG_CUSTOM_IMAGE_SPACINGY,
164 true );
165 imageOffset = bmp.GetWidth();
166 }
167
168 return imageOffset;
169}
170
171// -----------------------------------------------------------------------
172// wxPGDefaultRenderer
173// -----------------------------------------------------------------------
174
175void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect,
176 const wxPropertyGrid* propertyGrid, wxPGProperty* property,
177 int column, int item, int flags ) const
178{
179 bool isUnspecified = property->IsValueUnspecified();
180
181 if ( column == 1 && item == -1 )
182 {
183 int cmnVal = property->GetCommonValue();
184 if ( cmnVal >= 0 )
185 {
186 // Common Value
187 if ( !isUnspecified )
188 DrawText( dc, rect, 0, propertyGrid->GetCommonValueLabel(cmnVal) );
189 return;
190 }
191 }
192
193 const wxPGEditor* editor = NULL;
d7e2b522 194 const wxPGCell* cell = NULL;
1c4293cb
VZ
195
196 wxString text;
197 int imageOffset = 0;
d7e2b522 198 int preDrawFlags = flags;
1c4293cb 199
d7e2b522 200 property->GetDisplayInfo(column, item, flags, &text, &cell);
1c4293cb 201
d7e2b522 202 imageOffset = PreDrawCell( dc, rect, *cell, preDrawFlags );
1c4293cb 203
d7e2b522 204 if ( column == 1 )
1c4293cb
VZ
205 {
206 if ( !isUnspecified )
207 {
208 editor = property->GetColumnEditor(column);
209
210 // Regular property value
211
212 wxSize imageSize = propertyGrid->GetImageSize(property, item);
213
214 wxPGPaintData paintdata;
215 paintdata.m_parent = propertyGrid;
216 paintdata.m_choiceItem = item;
217
218 if ( imageSize.x > 0 )
219 {
220 wxRect imageRect(rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1,
221 rect.y+wxPG_CUSTOM_IMAGE_SPACINGY,
222 wxPG_CUSTOM_IMAGE_WIDTH,
223 rect.height-(wxPG_CUSTOM_IMAGE_SPACINGY*2));
224
1c4293cb
VZ
225 dc.SetPen( wxPen(propertyGrid->GetCellTextColour(), 1, wxSOLID) );
226
227 paintdata.m_drawnWidth = imageSize.x;
228 paintdata.m_drawnHeight = imageSize.y;
229
b7bc9d80 230 property->OnCustomPaint( dc, imageRect, paintdata );
1c4293cb
VZ
231
232 imageOffset = paintdata.m_drawnWidth;
233 }
234
1425eca5 235 text = property->GetValueAsString();
1c4293cb
VZ
236
237 // Add units string?
238 if ( propertyGrid->GetColumnCount() <= 2 )
239 {
240 wxString unitsString = property->GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
241 if ( unitsString.length() )
242 text = wxString::Format(wxS("%s %s"), text.c_str(), unitsString.c_str() );
243 }
244 }
245
246 if ( text.length() == 0 )
247 {
248 // Try to show inline help if no text
249 wxVariant vInlineHelp = property->GetAttribute(wxPGGlobalVars->m_strInlineHelp);
250 if ( !vInlineHelp.IsNull() )
251 {
252 text = vInlineHelp.GetString();
253 dc.SetTextForeground(propertyGrid->GetCellDisabledTextColour());
254 }
255 }
256 }
1c4293cb
VZ
257
258 DrawEditorValue( dc, rect, imageOffset, text, property, editor );
259
260 // active caption gets nice dotted rectangle
261 if ( property->IsCategory() /*&& column == 0*/ )
262 {
263 if ( flags & Selected )
264 {
265 if ( imageOffset > 0 )
266 imageOffset += wxCC_CUSTOM_IMAGE_MARGIN2 + 4;
267
268 DrawCaptionSelectionRect( dc,
269 rect.x+wxPG_XBEFORETEXT-wxPG_CAPRECTXMARGIN+imageOffset,
270 rect.y-wxPG_CAPRECTYMARGIN+1,
271 ((wxPropertyCategory*)property)->GetTextExtent(propertyGrid,
272 propertyGrid->GetCaptionFont())
273 +(wxPG_CAPRECTXMARGIN*2),
274 propertyGrid->GetFontHeight()+(wxPG_CAPRECTYMARGIN*2) );
275 }
276 }
277}
278
279wxSize wxPGDefaultRenderer::GetImageSize( const wxPGProperty* property,
280 int column,
281 int item ) const
282{
283 if ( property && column == 1 )
284 {
285 if ( item == -1 )
286 {
287 wxBitmap* bmp = property->GetValueImage();
288
289 if ( bmp && bmp->Ok() )
290 return wxSize(bmp->GetWidth(),bmp->GetHeight());
291 }
292 }
293 return wxSize(0,0);
294}
295
d7e2b522
JS
296// -----------------------------------------------------------------------
297// wxPGCellData
298// -----------------------------------------------------------------------
299
300wxPGCellData::wxPGCellData()
301 : wxObjectRefData()
302{
303 m_hasValidText = false;
304}
305
1c4293cb
VZ
306// -----------------------------------------------------------------------
307// wxPGCell
308// -----------------------------------------------------------------------
309
310wxPGCell::wxPGCell()
d7e2b522 311 : wxObject()
1c4293cb
VZ
312{
313}
314
315wxPGCell::wxPGCell( const wxString& text,
316 const wxBitmap& bitmap,
317 const wxColour& fgCol,
318 const wxColour& bgCol )
d7e2b522
JS
319 : wxObject()
320{
321 wxPGCellData* data = new wxPGCellData();
322 m_refData = data;
323 data->m_text = text;
324 data->m_bitmap = bitmap;
325 data->m_fgCol = fgCol;
326 data->m_bgCol = bgCol;
327 data->m_hasValidText = true;
328}
329
330wxObjectRefData *wxPGCell::CloneRefData( const wxObjectRefData *data ) const
331{
332 wxPGCellData* c = new wxPGCellData();
333 const wxPGCellData* o = (const wxPGCellData*) data;
334 c->m_text = o->m_text;
335 c->m_bitmap = o->m_bitmap;
336 c->m_fgCol = o->m_fgCol;
337 c->m_bgCol = o->m_bgCol;
338 c->m_hasValidText = o->m_hasValidText;
339 return c;
340}
341
342void wxPGCell::SetText( const wxString& text )
343{
344 AllocExclusive();
345
346 GetData()->SetText(text);
347}
348
349void wxPGCell::SetBitmap( const wxBitmap& bitmap )
1c4293cb 350{
d7e2b522
JS
351 AllocExclusive();
352
353 GetData()->SetBitmap(bitmap);
354}
355
356void wxPGCell::SetFgCol( const wxColour& col )
357{
358 AllocExclusive();
359
360 GetData()->SetFgCol(col);
361}
362
363void wxPGCell::SetBgCol( const wxColour& col )
364{
365 AllocExclusive();
366
367 GetData()->SetBgCol(col);
368}
369
370void wxPGCell::MergeFrom( const wxPGCell& srcCell )
371{
372 AllocExclusive();
373
374 wxPGCellData* data = GetData();
375
376 if ( srcCell.HasText() )
377 data->SetText(srcCell.GetText());
378
379 if ( srcCell.GetFgCol().IsOk() )
380 data->SetFgCol(srcCell.GetFgCol());
381
382 if ( srcCell.GetBgCol().IsOk() )
383 data->SetBgCol(srcCell.GetBgCol());
384
385 if ( srcCell.GetBitmap().IsOk() )
386 data->SetBitmap(srcCell.GetBitmap());
1c4293cb
VZ
387}
388
389// -----------------------------------------------------------------------
390// wxPGProperty
391// -----------------------------------------------------------------------
392
393IMPLEMENT_ABSTRACT_CLASS(wxPGProperty, wxObject)
394
395wxString* wxPGProperty::sm_wxPG_LABEL = NULL;
396
397void wxPGProperty::Init()
398{
399 m_commonValue = -1;
400 m_arrIndex = 0xFFFF;
401 m_parent = NULL;
402
403 m_parentState = (wxPropertyGridPageState*) NULL;
404
405 m_clientData = NULL;
406 m_clientObject = NULL;
407
408 m_customEditor = (wxPGEditor*) NULL;
409#if wxUSE_VALIDATORS
410 m_validator = (wxValidator*) NULL;
411#endif
412 m_valueBitmap = (wxBitmap*) NULL;
413
414 m_maxLen = 0; // infinite maximum length
415
416 m_flags = wxPG_PROP_PROPERTY;
417
418 m_depth = 1;
1c4293cb
VZ
419
420 SetExpanded(true);
421}
422
423
424void wxPGProperty::Init( const wxString& label, const wxString& name )
425{
426 // We really need to check if &label and &name are NULL pointers
427 // (this can if we are called before property grid has been initalized)
428
429 if ( (&label) != NULL && label != wxPG_LABEL )
430 m_label = label;
431
432 if ( (&name) != NULL && name != wxPG_LABEL )
433 DoSetName( name );
434 else
435 DoSetName( m_label );
436
437 Init();
438}
439
2fd4a524
JS
440void wxPGProperty::InitAfterAdded( wxPropertyGridPageState* pageState,
441 wxPropertyGrid* propgrid )
442{
443 //
444 // Called after property has been added to grid or page
445 // (so propgrid can be NULL, too).
446
447 wxPGProperty* parent = m_parent;
448 bool parentIsRoot = parent->IsKindOf(CLASSINFO(wxPGRootProperty));
449
450 m_parentState = pageState;
451
1425eca5
JS
452#if wxPG_COMPATIBILITY_1_4
453 // Make sure deprecated virtual functions are not implemented
454 wxString s = GetValueAsString( 0xFFFF );
455 wxASSERT_MSG( s == g_invalidStringContent,
456 "Implement ValueToString() instead of GetValueAsString()" );
457#endif
458
d7e2b522 459 if ( !parentIsRoot && !parent->IsCategory() )
2fd4a524 460 {
d7e2b522 461 m_cells = parent->m_cells;
2fd4a524
JS
462 }
463
464 // If in hideable adding mode, or if assigned parent is hideable, then
465 // make this one hideable.
466 if (
467 ( !parentIsRoot && parent->HasFlag(wxPG_PROP_HIDDEN) ) ||
468 ( propgrid && (propgrid->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES)) )
469 )
470 SetFlag( wxPG_PROP_HIDDEN );
471
472 // Set custom image flag.
473 int custImgHeight = OnMeasureImage().y;
474 if ( custImgHeight < 0 )
475 {
476 SetFlag(wxPG_PROP_CUSTOMIMAGE);
477 }
478
479 if ( propgrid && (propgrid->HasFlag(wxPG_LIMITED_EDITING)) )
480 SetFlag(wxPG_PROP_NOEDITOR);
481
482 // Make sure parent has some parental flags
483 if ( !parent->HasFlag(wxPG_PROP_PARENTAL_FLAGS) )
484 parent->SetParentalType(wxPG_PROP_MISC_PARENT);
485
486 if ( !IsCategory() )
487 {
488 // This is not a category.
489
490 // Depth.
491 //
492 unsigned char depth = 1;
493 if ( !parentIsRoot )
494 {
495 depth = parent->m_depth;
496 if ( !parent->IsCategory() )
497 depth++;
498 }
499 m_depth = depth;
500 unsigned char greyDepth = depth;
501
502 if ( !parentIsRoot )
503 {
504 wxPropertyCategory* pc;
505
506 if ( parent->IsCategory() )
507 pc = (wxPropertyCategory* ) parent;
508 else
509 // This conditional compile is necessary to
510 // bypass some compiler bug.
511 pc = pageState->GetPropertyCategory(parent);
512
513 if ( pc )
514 greyDepth = pc->GetDepth();
515 else
516 greyDepth = parent->m_depthBgCol;
517 }
518
519 m_depthBgCol = greyDepth;
520 }
521 else
522 {
523 // This is a category.
524
525 // depth
526 unsigned char depth = 1;
527 if ( !parentIsRoot )
528 {
529 depth = parent->m_depth + 1;
530 }
531 m_depth = depth;
532 m_depthBgCol = depth;
533 }
534
535 //
536 // Has initial children
537 if ( GetChildCount() )
538 {
2fd4a524 539 // Check parental flags
b0f0eda8 540 wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS),
2fd4a524
JS
541 "Call SetFlag(wxPG_PROP_MISC_PARENT) or"
542 "SetFlag(wxPG_PROP_AGGREGATE) before calling"
543 "wxPGProperty::AddChild()." );
544
545 if ( HasFlag(wxPG_PROP_AGGREGATE) )
546 {
547 // Properties with private children are not expanded by default.
548 SetExpanded(false);
549 }
550 else if ( propgrid && propgrid->HasFlag(wxPG_HIDE_MARGIN) )
551 {
552 // ...unless it cannot be expanded by user and therefore must
553 // remain visible at all times
554 SetExpanded(true);
555 }
556
557 //
558 // Prepare children recursively
559 for ( unsigned int i=0; i<GetChildCount(); i++ )
560 {
561 wxPGProperty* child = Item(i);
562 child->InitAfterAdded(pageState, pageState->GetGrid());
563 }
564
565 if ( propgrid && (propgrid->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES) )
566 SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED, true);
567 }
568}
569
1c4293cb
VZ
570wxPGProperty::wxPGProperty()
571 : wxObject()
572{
573 Init();
574}
575
576
577wxPGProperty::wxPGProperty( const wxString& label, const wxString& name )
578 : wxObject()
579{
580 Init( label, name );
581}
582
583
584wxPGProperty::~wxPGProperty()
585{
586 delete m_clientObject;
587
588 Empty(); // this deletes items
589
590 delete m_valueBitmap;
591#if wxUSE_VALIDATORS
592 delete m_validator;
593#endif
594
1c4293cb
VZ
595 // This makes it easier for us to detect dangling pointers
596 m_parent = NULL;
597}
598
599
600bool wxPGProperty::IsSomeParent( wxPGProperty* candidate ) const
601{
602 wxPGProperty* parent = m_parent;
603 do
604 {
605 if ( parent == candidate )
606 return true;
607 parent = parent->m_parent;
608 } while ( parent );
609 return false;
610}
611
612
613wxString wxPGProperty::GetName() const
614{
615 wxPGProperty* parent = GetParent();
616
617 if ( !m_name.length() || !parent || parent->IsCategory() || parent->IsRoot() )
618 return m_name;
619
620 return m_parent->GetName() + wxS(".") + m_name;
621}
622
623wxPropertyGrid* wxPGProperty::GetGrid() const
624{
625 if ( !m_parentState )
626 return NULL;
627 return m_parentState->GetGrid();
628}
629
f7a094e1
JS
630int wxPGProperty::Index( const wxPGProperty* p ) const
631{
632 for ( unsigned int i = 0; i<m_children.size(); i++ )
633 {
634 if ( p == m_children[i] )
635 return i;
636 }
637 return wxNOT_FOUND;
638}
1c4293cb
VZ
639
640void wxPGProperty::UpdateControl( wxWindow* primary )
641{
642 if ( primary )
643 GetEditorClass()->UpdateControl(this, primary);
644}
645
646bool wxPGProperty::ValidateValue( wxVariant& WXUNUSED(value), wxPGValidationInfo& WXUNUSED(validationInfo) ) const
647{
648 return true;
649}
650
651void wxPGProperty::OnSetValue()
652{
653}
654
655void wxPGProperty::RefreshChildren ()
656{
657}
658
d7e2b522
JS
659void wxPGProperty::GetDisplayInfo( unsigned int column,
660 int choiceIndex,
661 int flags,
662 wxString* pString,
663 const wxPGCell** pCell )
664{
665 const wxPGCell* cell = NULL;
666
667 if ( !(flags & wxPGCellRenderer::ChoicePopup) )
668 {
669 // Not painting listi of choice popups, so get text from property
670 cell = &GetCell(column);
671 if ( cell->HasText() )
672 {
673 *pString = cell->GetText();
674 }
675 else
676 {
677 if ( column == 0 )
678 *pString = GetLabel();
679 else if ( column == 1 )
680 *pString = GetDisplayedString();
681 else if ( column == 2 )
682 *pString = GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
683 }
684 }
685 else
686 {
687 wxASSERT( column == 1 );
688
689 if ( choiceIndex != wxNOT_FOUND )
690 {
691 const wxPGChoiceEntry& entry = m_choices[choiceIndex];
692 if ( entry.GetBitmap().IsOk() ||
693 entry.GetFgCol().IsOk() ||
694 entry.GetBgCol().IsOk() )
695 cell = &entry;
696 *pString = m_choices.GetLabel(choiceIndex);
697 }
698 }
699
700 if ( !cell )
701 cell = &GetCell(column);
702
703 wxASSERT_MSG( cell->GetData(),
704 wxString::Format("Invalid cell for property %s",
705 GetName().c_str()) );
706
707 *pCell = cell;
708}
709
710/*
711wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
1c4293cb 712{
d7e2b522
JS
713
714 if ( col != 1 || choiceIndex == wxNOT_FOUND )
1c4293cb 715 {
d7e2b522
JS
716 const wxPGCell& cell = GetCell(col);
717 if ( cell->HasText() )
718 {
719 return cell->GetText();
720 }
721 else
722 {
723 if ( col == 0 )
724 return GetLabel();
725 else if ( col == 1 )
726 return GetDisplayedString();
727 else if ( col == 2 )
728 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
729 }
1c4293cb
VZ
730 }
731 else
732 {
d7e2b522
JS
733 // Use choice
734 return m_choices.GetLabel(choiceIndex);
1c4293cb
VZ
735 }
736
737 return wxEmptyString;
738}
d7e2b522 739*/
1c4293cb 740
c82a80e8
JS
741void wxPGProperty::DoGenerateComposedValue( wxString& text,
742 int argFlags,
743 const wxVariantList* valueOverrides,
744 wxPGHashMapS2S* childResults ) const
1c4293cb
VZ
745{
746 int i;
f7a094e1 747 int iMax = m_children.size();
1c4293cb
VZ
748
749 text.clear();
750 if ( iMax == 0 )
751 return;
752
753 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
754 !(argFlags & wxPG_FULL_VALUE) )
755 iMax = PWC_CHILD_SUMMARY_LIMIT;
756
757 int iMaxMinusOne = iMax-1;
758
759 if ( !IsTextEditable() )
760 argFlags |= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT;
761
f7a094e1 762 wxPGProperty* curChild = m_children[0];
1c4293cb 763
1425eca5
JS
764 bool overridesLeft = false;
765 wxVariant overrideValue;
766 wxVariantList::const_iterator node;
767
768 if ( valueOverrides )
769 {
770 node = valueOverrides->begin();
771 if ( node != valueOverrides->end() )
772 {
773 overrideValue = *node;
774 overridesLeft = true;
775 }
776 }
777
1c4293cb
VZ
778 for ( i = 0; i < iMax; i++ )
779 {
1425eca5
JS
780 wxVariant childValue;
781
782 wxString childLabel = curChild->GetLabel();
783
784 // Check for value override
785 if ( overridesLeft && overrideValue.GetName() == childLabel )
786 {
787 if ( !overrideValue.IsNull() )
788 childValue = overrideValue;
789 else
790 childValue = curChild->GetValue();
b7bc9d80 791 ++node;
1425eca5
JS
792 if ( node != valueOverrides->end() )
793 overrideValue = *node;
794 else
795 overridesLeft = false;
796 }
797 else
798 {
799 childValue = curChild->GetValue();
800 }
801
1c4293cb 802 wxString s;
1425eca5
JS
803 if ( !childValue.IsNull() )
804 {
805 if ( overridesLeft &&
806 curChild->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
807 childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
808 {
809 wxVariantList& childList = childValue.GetList();
c82a80e8
JS
810 DoGenerateComposedValue(s, argFlags|wxPG_COMPOSITE_FRAGMENT,
811 &childList, childResults);
1425eca5
JS
812 }
813 else
814 {
815 s = curChild->ValueToString(childValue,
816 argFlags|wxPG_COMPOSITE_FRAGMENT);
817 }
818 }
819
820 if ( childResults && curChild->GetChildCount() )
821 (*childResults)[curChild->GetName()] = s;
1c4293cb
VZ
822
823 bool skip = false;
824 if ( (argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT) && !s.length() )
825 skip = true;
826
827 if ( !curChild->GetChildCount() || skip )
828 text += s;
829 else
830 text += wxS("[") + s + wxS("]");
831
832 if ( i < iMaxMinusOne )
833 {
834 if ( text.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT &&
835 !(argFlags & wxPG_EDITABLE_VALUE) &&
836 !(argFlags & wxPG_FULL_VALUE) )
837 break;
838
839 if ( !skip )
840 {
841 if ( !curChild->GetChildCount() )
842 text += wxS("; ");
843 else
844 text += wxS(" ");
845 }
846
f7a094e1 847 curChild = m_children[i+1];
1c4293cb
VZ
848 }
849 }
850
f7a094e1 851 if ( (unsigned int)i < m_children.size() )
7036fd20
JS
852 {
853 if ( !text.EndsWith(wxS("; ")) )
854 text += wxS("; ...");
855 else
856 text += wxS("...");
857 }
1c4293cb
VZ
858}
859
1425eca5
JS
860wxString wxPGProperty::ValueToString( wxVariant& WXUNUSED(value),
861 int argFlags ) const
1c4293cb
VZ
862{
863 wxCHECK_MSG( GetChildCount() > 0,
864 wxString(),
1425eca5
JS
865 "If user property does not have any children, it must "
866 "override GetValueAsString" );
867
868 // FIXME: Currently code below only works if value is actually m_value
869 wxASSERT_MSG( argFlags & wxPG_VALUE_IS_CURRENT,
870 "Sorry, currently default wxPGProperty::ValueToString() "
871 "implementation only works if value is m_value." );
1c4293cb
VZ
872
873 wxString text;
c82a80e8 874 DoGenerateComposedValue(text, argFlags);
1c4293cb
VZ
875 return text;
876}
877
1425eca5 878wxString wxPGProperty::GetValueAsString( int argFlags ) const
1c4293cb 879{
1425eca5
JS
880#if wxPG_COMPATIBILITY_1_4
881 // This is backwards compatibility test
882 // That is, to make sure this function is not overridden
883 // (instead, ValueToString() should be).
884 if ( argFlags == 0xFFFF )
885 {
886 // Do not override! (for backwards compliancy)
887 return g_invalidStringContent;
888 }
889#endif
890
1c4293cb
VZ
891 if ( IsValueUnspecified() )
892 return wxEmptyString;
893
894 if ( m_commonValue == -1 )
1425eca5
JS
895 {
896 wxVariant value(GetValue());
897 return ValueToString(value, argFlags|wxPG_VALUE_IS_CURRENT);
898 }
1c4293cb
VZ
899
900 //
901 // Return common value's string representation
902 wxPropertyGrid* pg = GetGrid();
903 const wxPGCommonValue* cv = pg->GetCommonValue(m_commonValue);
904
905 if ( argFlags & wxPG_FULL_VALUE )
906 {
907 return cv->GetLabel();
908 }
909 else if ( argFlags & wxPG_EDITABLE_VALUE )
910 {
911 return cv->GetEditableText();
912 }
913 else
914 {
915 return cv->GetLabel();
916 }
917}
918
1425eca5
JS
919wxString wxPGProperty::GetValueString( int argFlags ) const
920{
921 return GetValueAsString(argFlags);
922}
923
1c4293cb
VZ
924bool wxPGProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const
925{
926 variant = (long)number;
927 return true;
928}
929
930// Convert semicolon delimited tokens into child values.
931bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
932{
933 if ( !GetChildCount() )
934 return false;
935
936 unsigned int curChild = 0;
937
f7a094e1 938 unsigned int iMax = m_children.size();
1c4293cb
VZ
939
940 if ( iMax > PWC_CHILD_SUMMARY_LIMIT &&
941 !(argFlags & wxPG_FULL_VALUE) )
942 iMax = PWC_CHILD_SUMMARY_LIMIT;
943
944 bool changed = false;
945
946 wxString token;
947 size_t pos = 0;
948
949 // Its best only to add non-empty group items
950 bool addOnlyIfNotEmpty = false;
951 const wxChar delimeter = wxS(';');
952
953 size_t tokenStart = 0xFFFFFF;
954
955 wxVariantList temp_list;
956 wxVariant list(temp_list);
957
f275b5db 958 int propagatedFlags = argFlags & (wxPG_REPORT_ERROR|wxPG_PROGRAMMATIC_VALUE);
1c4293cb
VZ
959
960#ifdef __WXDEBUG__
961 bool debug_print = false;
962#endif
963
964#ifdef __WXDEBUG__
965 if ( debug_print )
966 wxLogDebug(wxT(">> %s.StringToValue('%s')"),GetLabel().c_str(),text.c_str());
967#endif
968
969 wxString::const_iterator it = text.begin();
970 wxUniChar a;
971
972 if ( it != text.end() )
973 a = *it;
974 else
975 a = 0;
976
977 for ( ;; )
978 {
979 if ( tokenStart != 0xFFFFFF )
980 {
981 // Token is running
982 if ( a == delimeter || a == 0 )
983 {
984 token = text.substr(tokenStart,pos-tokenStart);
985 token.Trim(true);
986 size_t len = token.length();
987
988 if ( !addOnlyIfNotEmpty || len > 0 )
989 {
990 const wxPGProperty* child = Item(curChild);
f275b5db
JS
991 wxVariant variant(child->GetValue());
992 variant.SetName(child->GetBaseName());
993
1c4293cb
VZ
994 #ifdef __WXDEBUG__
995 if ( debug_print )
996 wxLogDebug(wxT("token = '%s', child = %s"),token.c_str(),child->GetLabel().c_str());
997 #endif
998
f275b5db
JS
999 // Add only if editable or setting programmatically
1000 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
1001 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1c4293cb 1002 {
f275b5db 1003 if ( len > 0 )
1c4293cb 1004 {
f275b5db 1005 if ( child->StringToValue(variant, token, propagatedFlags|wxPG_COMPOSITE_FRAGMENT) )
1c4293cb 1006 {
f275b5db 1007 list.Append(variant);
1c4293cb 1008
f275b5db
JS
1009 changed = true;
1010 }
1011 }
1012 else
1013 {
1014 // Empty, becomes unspecified
1015 variant.MakeNull();
1016 list.Append(variant);
1c4293cb
VZ
1017 changed = true;
1018 }
1019 }
1c4293cb
VZ
1020
1021 curChild++;
1022 if ( curChild >= iMax )
1023 break;
1024 }
1025
1026 tokenStart = 0xFFFFFF;
1027 }
1028 }
1029 else
1030 {
1031 // Token is not running
1032 if ( a != wxS(' ') )
1033 {
1034
1035 addOnlyIfNotEmpty = false;
1036
1037 // Is this a group of tokens?
1038 if ( a == wxS('[') )
1039 {
1040 int depth = 1;
1041
b7bc9d80 1042 if ( it != text.end() ) ++it;
1c4293cb
VZ
1043 pos++;
1044 size_t startPos = pos;
1045
1046 // Group item - find end
1047 while ( it != text.end() && depth > 0 )
1048 {
1049 a = *it;
b7bc9d80 1050 ++it;
1c4293cb
VZ
1051 pos++;
1052
1053 if ( a == wxS(']') )
1054 depth--;
1055 else if ( a == wxS('[') )
1056 depth++;
1057 }
1058
1059 token = text.substr(startPos,pos-startPos-1);
1060
1061 if ( !token.length() )
1062 break;
1063
1064 const wxPGProperty* child = Item(curChild);
1065
2bbd3749
JS
1066 wxVariant oldChildValue = child->GetValue();
1067 wxVariant variant(oldChildValue);
f275b5db
JS
1068
1069 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
1070 !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) )
1c4293cb 1071 {
f275b5db
JS
1072 bool stvRes = child->StringToValue( variant, token, propagatedFlags );
1073 if ( stvRes || (variant != oldChildValue) )
1074 {
1075 if ( stvRes )
1076 changed = true;
1077 }
1078 else
1079 {
1080 // Failed, becomes unspecified
1081 variant.MakeNull();
2bbd3749 1082 changed = true;
f275b5db 1083 }
1c4293cb
VZ
1084 }
1085
2bbd3749
JS
1086 variant.SetName(child->GetBaseName());
1087 list.Append(variant);
1088
1c4293cb
VZ
1089 curChild++;
1090 if ( curChild >= iMax )
1091 break;
1092
1093 addOnlyIfNotEmpty = true;
1094
1095 tokenStart = 0xFFFFFF;
1096 }
1097 else
1098 {
1099 tokenStart = pos;
1100
1101 if ( a == delimeter )
1102 {
1103 pos--;
b7bc9d80 1104 --it;
1c4293cb
VZ
1105 }
1106 }
1107 }
1108 }
1109
1110 if ( a == 0 )
1111 break;
1112
b7bc9d80 1113 ++it;
1c4293cb
VZ
1114 if ( it != text.end() )
1115 {
1116 a = *it;
1117 }
1118 else
1119 {
1120 a = 0;
1121 }
1122 pos++;
1123 }
1124
1125 if ( changed )
1126 variant = list;
1127
1128 return changed;
1129}
1130
1131bool wxPGProperty::SetValueFromString( const wxString& text, int argFlags )
1132{
1133 wxVariant variant(m_value);
1134 bool res = StringToValue(variant, text, argFlags);
1135 if ( res )
1136 SetValue(variant);
1137 return res;
1138}
1139
1140bool wxPGProperty::SetValueFromInt( long number, int argFlags )
1141{
1142 wxVariant variant(m_value);
1143 bool res = IntToValue(variant, number, argFlags);
1144 if ( res )
1145 SetValue(variant);
1146 return res;
1147}
1148
1149wxSize wxPGProperty::OnMeasureImage( int WXUNUSED(item) ) const
1150{
1151 if ( m_valueBitmap )
1152 return wxSize(m_valueBitmap->GetWidth(),-1);
1153
1154 return wxSize(0,0);
1155}
1156
1157wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const
1158{
1159 return wxPGGlobalVars->m_defaultRenderer;
1160}
1161
1162void wxPGProperty::OnCustomPaint( wxDC& dc,
1163 const wxRect& rect,
1164 wxPGPaintData& )
1165{
1166 wxBitmap* bmp = m_valueBitmap;
1167
1168 wxCHECK_RET( bmp && bmp->Ok(), wxT("invalid bitmap") );
1169
1170 wxCHECK_RET( rect.x >= 0, wxT("unexpected measure call") );
1171
1172 dc.DrawBitmap(*bmp,rect.x,rect.y);
1173}
1174
1175const wxPGEditor* wxPGProperty::DoGetEditorClass() const
1176{
c26873c8 1177 return wxPGEditor_TextCtrl;
1c4293cb
VZ
1178}
1179
1180// Default extra property event handling - that is, none at all.
1181bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& )
1182{
1183 return false;
1184}
1185
1186
1187void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags )
1188{
104837f2
JS
1189 // If auto unspecified values are not wanted (via window or property style),
1190 // then get default value instead of wxNullVariant.
1191 if ( value.IsNull() && (flags & wxPG_SETVAL_BY_USER) &&
1192 !UsesAutoUnspecified() )
1193 {
1194 value = GetDefaultValue();
1195 }
1196
1c4293cb
VZ
1197 if ( !value.IsNull() )
1198 {
8f18b252
JS
1199 wxVariant tempListVariant;
1200
1c4293cb
VZ
1201 SetCommonValue(-1);
1202 // List variants are reserved a special purpose
1203 // as intermediate containers for child values
1204 // of properties with children.
0372d42e 1205 if ( value.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb 1206 {
8f18b252
JS
1207 //
1208 // However, situation is different for composed string properties
1209 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
1210 {
1211 tempListVariant = value;
1212 pList = &tempListVariant;
1213 }
1214
1c4293cb
VZ
1215 wxVariant newValue;
1216 AdaptListToValue(value, &newValue);
1217 value = newValue;
1218 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1219 }
1220
1221 if ( HasFlag( wxPG_PROP_AGGREGATE) )
1222 flags |= wxPG_SETVAL_AGGREGATED;
1223
1224 if ( pList && !pList->IsNull() )
1225 {
0372d42e 1226 wxASSERT( pList->GetType() == wxPG_VARIANT_TYPE_LIST );
1c4293cb
VZ
1227 wxASSERT( GetChildCount() );
1228 wxASSERT( !IsCategory() );
1229
1230 wxVariantList& list = pList->GetList();
1231 wxVariantList::iterator node;
1232 unsigned int i = 0;
1233
1234 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1235
1236 // Children in list can be in any order, but we will give hint to
d665918b 1237 // GetPropertyByNameWH(). This optimizes for full list parsing.
b7bc9d80 1238 for ( node = list.begin(); node != list.end(); ++node )
1c4293cb
VZ
1239 {
1240 wxVariant& childValue = *((wxVariant*)*node);
d665918b 1241 wxPGProperty* child = GetPropertyByNameWH(childValue.GetName(), i);
1c4293cb
VZ
1242 if ( child )
1243 {
d665918b 1244 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
0372d42e 1245 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
1246 {
1247 if ( child->HasFlag(wxPG_PROP_AGGREGATE) && !(flags & wxPG_SETVAL_AGGREGATED) )
1248 {
1249 wxVariant listRefCopy = childValue;
1250 child->SetValue(childValue, &listRefCopy, flags|wxPG_SETVAL_FROM_PARENT);
1251 }
1252 else
1253 {
1254 wxVariant oldVal = child->GetValue();
1255 child->SetValue(oldVal, &childValue, flags|wxPG_SETVAL_FROM_PARENT);
1256 }
1257 }
0372d42e 1258 else if ( child->GetValue() != childValue )
1c4293cb
VZ
1259 {
1260 // For aggregate properties, we will trust RefreshChildren()
1261 // to update child values.
1262 if ( !HasFlag(wxPG_PROP_AGGREGATE) )
1263 child->SetValue(childValue, NULL, flags|wxPG_SETVAL_FROM_PARENT);
8f18b252
JS
1264 if ( flags & wxPG_SETVAL_BY_USER )
1265 child->SetFlag(wxPG_PROP_MODIFIED);
1c4293cb
VZ
1266 }
1267 }
1268 i++;
1269 }
1270 }
1271
1272 if ( !value.IsNull() )
1273 {
0372d42e 1274 m_value = value;
1c4293cb
VZ
1275 OnSetValue();
1276
1277 if ( !(flags & wxPG_SETVAL_FROM_PARENT) )
1278 UpdateParentValues();
1279 }
1280
8f18b252 1281 if ( flags & wxPG_SETVAL_BY_USER )
1c4293cb
VZ
1282 SetFlag(wxPG_PROP_MODIFIED);
1283
1284 if ( HasFlag(wxPG_PROP_AGGREGATE) )
1285 RefreshChildren();
1286 }
1287 else
1288 {
1289 if ( m_commonValue != -1 )
1290 {
1291 wxPropertyGrid* pg = GetGrid();
1292 if ( !pg || m_commonValue != pg->GetUnspecifiedCommonValue() )
1293 SetCommonValue(-1);
1294 }
1295
1296 m_value = value;
1297
1298 // Set children to unspecified, but only if aggregate or
1299 // value is <composed>
1300 if ( AreChildrenComponents() )
1301 {
1302 unsigned int i;
1303 for ( i=0; i<GetChildCount(); i++ )
1304 Item(i)->SetValue(value, NULL, flags|wxPG_SETVAL_FROM_PARENT);
1305 }
1306 }
1307
1308 //
1309 // Update editor control
1310 //
1311
1312 // We need to check for these, otherwise GetGrid() may fail.
1313 if ( flags & wxPG_SETVAL_REFRESH_EDITOR )
1314 RefreshEditor();
1315}
1316
1317
1318void wxPGProperty::SetValueInEvent( wxVariant value ) const
1319{
1320 GetGrid()->ValueChangeInEvent(value);
1321}
1322
1323void wxPGProperty::SetFlagRecursively( FlagType flag, bool set )
1324{
1325 if ( set )
1326 SetFlag(flag);
1327 else
1328 ClearFlag(flag);
1329
1330 unsigned int i;
1331 for ( i = 0; i < GetChildCount(); i++ )
1332 Item(i)->SetFlagRecursively(flag, set);
1333}
1334
1335void wxPGProperty::RefreshEditor()
1336{
1337 if ( m_parent && GetParentState() )
1338 {
1339 wxPropertyGrid* pg = GetParentState()->GetGrid();
1340 if ( pg->GetSelectedProperty() == this )
1341 {
1342 wxWindow* editor = pg->GetEditorControl();
1343 if ( editor )
1344 GetEditorClass()->UpdateControl( this, editor );
1345 }
1346 }
1347}
1348
1349
1350wxVariant wxPGProperty::GetDefaultValue() const
1351{
1352 wxVariant defVal = GetAttribute(wxS("DefaultValue"));
1353 if ( !defVal.IsNull() )
1354 return defVal;
1355
1356 wxVariant value = GetValue();
1357
1358 if ( !value.IsNull() )
1359 {
0372d42e
JS
1360 wxString valueType(value.GetType());
1361
1362 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1c4293cb 1363 return wxPGVariant_Zero;
0372d42e 1364 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1c4293cb 1365 return wxPGVariant_EmptyString;
0372d42e 1366 if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1c4293cb 1367 return wxPGVariant_False;
0372d42e 1368 if ( valueType == wxPG_VARIANT_TYPE_DOUBLE )
1c4293cb 1369 return wxVariant(0.0);
0372d42e 1370 if ( valueType == wxPG_VARIANT_TYPE_ARRSTRING )
1c4293cb 1371 return wxVariant(wxArrayString());
0372d42e
JS
1372 if ( valueType == wxS("wxLongLong") )
1373 return WXVARIANT(wxLongLong(0));
1374 if ( valueType == wxS("wxULongLong") )
1375 return WXVARIANT(wxULongLong(0));
1376 if ( valueType == wxS("wxColour") )
1377 return WXVARIANT(*wxBLACK);
1c4293cb 1378#if wxUSE_DATETIME
0372d42e 1379 if ( valueType == wxPG_VARIANT_TYPE_DATETIME )
1c4293cb
VZ
1380 return wxVariant(wxDateTime::Now());
1381#endif
0372d42e
JS
1382 if ( valueType == wxS("wxFont") )
1383 return WXVARIANT(*wxNORMAL_FONT);
1384 if ( valueType == wxS("wxPoint") )
1385 return WXVARIANT(wxPoint(0, 0));
1386 if ( valueType == wxS("wxSize") )
1387 return WXVARIANT(wxSize(0, 0));
1c4293cb
VZ
1388 }
1389
1390 return wxVariant();
1391}
1392
d7e2b522
JS
1393void wxPGProperty::EnsureCells( unsigned int column )
1394{
1395 if ( column >= m_cells.size() )
1396 {
1397 // Fill empty slots with default cells
1398 wxPropertyGrid* pg = GetGrid();
1399 wxPGCell defaultCell;
1400
1401 if ( !HasFlag(wxPG_PROP_CATEGORY) )
1402 defaultCell = pg->GetPropertyDefaultCell();
1403 else
1404 defaultCell = pg->GetCategoryDefaultCell();
1405
1406 // TODO: Replace with resize() call
1407 unsigned int cellCountMax = column+1;
1408
1409 for ( unsigned int i=m_cells.size(); i<cellCountMax; i++ )
1410 m_cells.push_back(defaultCell);
1411 }
1412}
1413
1414void wxPGProperty::SetCell( int column,
1415 const wxPGCell& cell )
1416{
1417 EnsureCells(column);
1418
1419 m_cells[column] = cell;
1420}
1421
1422void wxPGProperty::AdaptiveSetCell( unsigned int firstCol,
1423 unsigned int lastCol,
1424 const wxPGCell& cell,
1425 const wxPGCell& srcData,
1426 wxPGCellData* unmodCellData,
1427 FlagType ignoreWithFlags,
1428 bool recursively )
1429{
1430 //
1431 // Sets cell in memory optimizing fashion. That is, if
1432 // current cell data matches unmodCellData, we will
1433 // simply get reference to data from cell. Otherwise,
1434 // cell information from srcData is merged into current.
1435 //
1436
1437 if ( !(m_flags & ignoreWithFlags) && !IsRoot() )
1438 {
1439 EnsureCells(lastCol);
1440
1441 for ( unsigned int col=firstCol; col<=lastCol; col++ )
1442 {
1443 if ( m_cells[col].GetData() == unmodCellData )
1444 {
1445 // Data matches... use cell directly
1446 m_cells[col] = cell;
1447 }
1448 else
1449 {
1450 // Data did not match... merge valid information
1451 m_cells[col].MergeFrom(srcData);
1452 }
1453 }
1454 }
1455
1456 if ( recursively )
1457 {
1458 for ( unsigned int i=0; i<GetChildCount(); i++ )
1459 Item(i)->AdaptiveSetCell( firstCol,
1460 lastCol,
1461 cell,
1462 srcData,
1463 unmodCellData,
1464 ignoreWithFlags,
1465 recursively );
1466 }
1467}
1468
1469const wxPGCell& wxPGProperty::GetCell( unsigned int column ) const
1c4293cb 1470{
d7e2b522
JS
1471 if ( m_cells.size() > column )
1472 return m_cells[column];
1473
1474 wxPropertyGrid* pg = GetGrid();
1475
1476 if ( IsCategory() )
1477 return pg->GetCategoryDefaultCell();
1478
1479 return pg->GetPropertyDefaultCell();
1480}
1481
1482wxPGCell& wxPGProperty::GetCell( unsigned int column )
1483{
1484 EnsureCells(column);
1485 return m_cells[column];
1486}
1487
1488void wxPGProperty::SetBackgroundColour( const wxColour& colour,
1489 bool recursively )
1490{
1491 wxPGProperty* firstProp = this;
1492
1493 //
1494 // If category is tried to set recursively, skip it and only
1495 // affect the children.
1496 if ( recursively )
1497 {
1498 while ( firstProp->IsCategory() )
1499 {
1500 if ( !firstProp->GetChildCount() )
1501 return;
1502 firstProp = firstProp->Item(0);
1503 }
1504 }
1505
1506 wxPGCell& firstCell = firstProp->GetCell(0);
1507 wxPGCellData* firstCellData = firstCell.GetData();
1508
1509 wxPGCell newCell(firstCell);
1510 newCell.SetBgCol(colour);
1511 wxPGCell srcCell;
1512 srcCell.SetBgCol(colour);
1513
1514 AdaptiveSetCell( 0,
1515 GetParentState()->GetColumnCount()-1,
1516 newCell,
1517 srcCell,
1518 firstCellData,
1519 recursively ? wxPG_PROP_CATEGORY : 0,
1520 recursively );
1521}
1522
1523void wxPGProperty::SetTextColour( const wxColour& colour,
1524 bool recursively )
1525{
1526 wxPGProperty* firstProp = this;
1527
1528 //
1529 // If category is tried to set recursively, skip it and only
1530 // affect the children.
1531 if ( recursively )
1532 {
1533 while ( firstProp->IsCategory() )
1534 {
1535 if ( !firstProp->GetChildCount() )
1536 return;
1537 firstProp = firstProp->Item(0);
1538 }
1539 }
1c4293cb 1540
d7e2b522
JS
1541 wxPGCell& firstCell = firstProp->GetCell(0);
1542 wxPGCellData* firstCellData = firstCell.GetData();
1543
1544 wxPGCell newCell(firstCell);
1545 newCell.SetFgCol(colour);
1546 wxPGCell srcCell;
1547 srcCell.SetFgCol(colour);
1548
1549 AdaptiveSetCell( 0,
1550 GetParentState()->GetColumnCount()-1,
1551 newCell,
1552 srcCell,
1553 firstCellData,
1554 recursively ? wxPG_PROP_CATEGORY : 0,
1555 recursively );
1c4293cb
VZ
1556}
1557
1c4293cb
VZ
1558wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const
1559{
1560 return NULL;
1561}
1562
1563bool wxPGProperty::DoSetAttribute( const wxString& WXUNUSED(name), wxVariant& WXUNUSED(value) )
1564{
1565 return false;
1566}
1567
1568void wxPGProperty::SetAttribute( const wxString& name, wxVariant value )
1569{
1570 if ( DoSetAttribute( name, value ) )
1571 {
1572 // Support working without grid, when possible
1573 if ( wxPGGlobalVars->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES ) )
1574 return;
1575 }
1576
1577 m_attributes.Set( name, value );
1578}
1579
1580void wxPGProperty::SetAttributes( const wxPGAttributeStorage& attributes )
1581{
1582 wxPGAttributeStorage::const_iterator it = attributes.StartIteration();
1583 wxVariant variant;
1584
1585 while ( attributes.GetNext(it, variant) )
1586 SetAttribute( variant.GetName(), variant );
1587}
1588
1589wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
1590{
1591 return wxVariant();
1592}
1593
1594
1595wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
1596{
1597 return m_attributes.FindValue(name);
1598}
1599
1600wxString wxPGProperty::GetAttribute( const wxString& name, const wxString& defVal ) const
1601{
1602 wxVariant variant = m_attributes.FindValue(name);
1603
1604 if ( !variant.IsNull() )
1605 return variant.GetString();
1606
1607 return defVal;
1608}
1609
1610long wxPGProperty::GetAttributeAsLong( const wxString& name, long defVal ) const
1611{
1612 wxVariant variant = m_attributes.FindValue(name);
1613
1614 return wxPGVariantToInt(variant, defVal);
1615}
1616
1617double wxPGProperty::GetAttributeAsDouble( const wxString& name, double defVal ) const
1618{
1619 double retVal;
1620 wxVariant variant = m_attributes.FindValue(name);
1621
1622 if ( wxPGVariantToDouble(variant, &retVal) )
1623 return retVal;
1624
1625 return defVal;
1626}
1627
1628wxVariant wxPGProperty::GetAttributesAsList() const
1629{
1630 wxVariantList tempList;
1631 wxVariant v( tempList, wxString::Format(wxS("@%s@attr"),m_name.c_str()) );
1632
1633 wxPGAttributeStorage::const_iterator it = m_attributes.StartIteration();
1634 wxVariant variant;
1635
1636 while ( m_attributes.GetNext(it, variant) )
1637 v.Append(variant);
1638
1639 return v;
1640}
1641
1642// Slots of utility flags are NULL
1643const unsigned int gs_propFlagToStringSize = 14;
1644
1645static const wxChar* gs_propFlagToString[gs_propFlagToStringSize] = {
1646 NULL,
1647 wxT("DISABLED"),
1648 wxT("HIDDEN"),
1649 NULL,
1650 wxT("NOEDITOR"),
1651 wxT("COLLAPSED"),
1652 NULL,
1653 NULL,
1654 NULL,
1655 NULL,
1656 NULL,
1657 NULL,
1658 NULL,
1659 NULL
1660};
1661
1662wxString wxPGProperty::GetFlagsAsString( FlagType flagsMask ) const
1663{
1664 wxString s;
1665 int relevantFlags = m_flags & flagsMask & wxPG_STRING_STORED_FLAGS;
1666 FlagType a = 1;
1667
1668 unsigned int i = 0;
1669 for ( i=0; i<gs_propFlagToStringSize; i++ )
1670 {
1671 if ( relevantFlags & a )
1672 {
1673 const wxChar* fs = gs_propFlagToString[i];
1674 wxASSERT(fs);
1675 if ( s.length() )
1676 s << wxS("|");
1677 s << fs;
1678 }
1679 a = a << 1;
1680 }
1681
1682 return s;
1683}
1684
1685void wxPGProperty::SetFlagsFromString( const wxString& str )
1686{
1687 FlagType flags = 0;
1688
1689 WX_PG_TOKENIZER1_BEGIN(str, wxS('|'))
1690 unsigned int i;
1691 for ( i=0; i<gs_propFlagToStringSize; i++ )
1692 {
1693 const wxChar* fs = gs_propFlagToString[i];
1694 if ( fs && str == fs )
1695 {
1696 flags |= (1<<i);
1697 break;
1698 }
1699 }
1700 WX_PG_TOKENIZER1_END()
1701
1702 m_flags = (m_flags & ~wxPG_STRING_STORED_FLAGS) | flags;
1703}
1704
1705wxValidator* wxPGProperty::DoGetValidator() const
1706{
1707 return (wxValidator*) NULL;
1708}
1709
939d9364 1710int wxPGProperty::InsertChoice( const wxString& label, int index, int value )
1c4293cb 1711{
939d9364
JS
1712 wxPropertyGrid* pg = GetGrid();
1713 int sel = GetChoiceSelection();
1714
1715 int newSel = sel;
1716
1717 if ( index == wxNOT_FOUND )
1718 index = m_choices.GetCount();
1719
1720 if ( index <= sel )
1721 newSel++;
1722
1723 m_choices.Insert(label, index, value);
1724
1725 if ( sel != newSel )
1726 SetChoiceSelection(newSel);
1727
1728 if ( this == pg->GetSelection() )
1729 GetEditorClass()->InsertItem(pg->GetEditorControl(),label,index);
1730
1731 return index;
1c4293cb
VZ
1732}
1733
939d9364
JS
1734
1735void wxPGProperty::DeleteChoice( int index )
1c4293cb 1736{
939d9364
JS
1737 wxPropertyGrid* pg = GetGrid();
1738
1739 int sel = GetChoiceSelection();
1740 int newSel = sel;
1741
1742 // Adjust current value
1743 if ( sel == index )
1744 {
1745 SetValueToUnspecified();
1746 newSel = 0;
1747 }
1748 else if ( index < sel )
1749 {
1750 newSel--;
1751 }
1752
1753 m_choices.RemoveAt(index);
1754
1755 if ( sel != newSel )
1756 SetChoiceSelection(newSel);
1757
1758 if ( this == pg->GetSelection() )
1759 GetEditorClass()->DeleteItem(pg->GetEditorControl(), index);
1c4293cb
VZ
1760}
1761
939d9364 1762int wxPGProperty::GetChoiceSelection() const
1c4293cb 1763{
939d9364
JS
1764 wxVariant value = GetValue();
1765 wxString valueType = value.GetType();
1766 int index = wxNOT_FOUND;
1767
1768 if ( IsValueUnspecified() || !m_choices.GetCount() )
1769 return wxNOT_FOUND;
1770
1771 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1772 {
1773 index = value.GetLong();
1774 }
1775 else if ( valueType == wxPG_VARIANT_TYPE_STRING )
1776 {
1777 index = m_choices.Index(value.GetString());
1778 }
1779 else if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1780 {
1781 index = value.GetBool()? 1 : 0;
1782 }
1783
1784 return index;
1c4293cb
VZ
1785}
1786
939d9364 1787void wxPGProperty::SetChoiceSelection( int newValue )
1c4293cb 1788{
939d9364
JS
1789 // Changes value of a property with choices, but only
1790 // works if the value type is long or string.
1791 wxString valueType = GetValue().GetType();
1792
1793 wxCHECK_RET( m_choices.IsOk(), wxT("invalid choiceinfo") );
1c4293cb 1794
939d9364
JS
1795 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1796 {
1797 SetValue( m_choices.GetLabel(newValue) );
1798 }
1799 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1800 {
1801 SetValue( (long) newValue );
1802 }
1c4293cb
VZ
1803}
1804
1805bool wxPGProperty::SetChoices( wxPGChoices& choices )
1806{
939d9364 1807 m_choices.Assign(choices);
1c4293cb 1808
1c4293cb 1809 {
939d9364
JS
1810 // This may be needed to trigger some initialization
1811 // (but don't do it if property is somewhat uninitialized)
1812 wxVariant defVal = GetDefaultValue();
1813 if ( defVal.IsNull() )
1814 return false;
1c4293cb 1815
939d9364 1816 SetValue(defVal);
1c4293cb 1817 }
939d9364
JS
1818
1819 return true;
1c4293cb
VZ
1820}
1821
1822
1823const wxPGEditor* wxPGProperty::GetEditorClass() const
1824{
1825 const wxPGEditor* editor;
1826
1827 if ( !m_customEditor )
1828 {
1829 editor = DoGetEditorClass();
1830 }
1831 else
1832 editor = m_customEditor;
1833
1834 //
1835 // Maybe override editor if common value specified
1836 if ( GetDisplayedCommonValueCount() )
1837 {
1838 // TextCtrlAndButton -> ComboBoxAndButton
1839 if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor)) )
c26873c8 1840 editor = wxPGEditor_ChoiceAndButton;
1c4293cb
VZ
1841
1842 // TextCtrl -> ComboBox
1843 else if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlEditor)) )
c26873c8 1844 editor = wxPGEditor_ComboBox;
1c4293cb
VZ
1845 }
1846
1847 return editor;
1848}
1849
1c4293cb
VZ
1850bool wxPGProperty::HasVisibleChildren() const
1851{
1852 unsigned int i;
1853
1854 for ( i=0; i<GetChildCount(); i++ )
1855 {
1856 wxPGProperty* child = Item(i);
1857
1858 if ( !child->HasFlag(wxPG_PROP_HIDDEN) )
1859 return true;
1860 }
1861
1862 return false;
1863}
1864
1c4293cb
VZ
1865bool wxPGProperty::RecreateEditor()
1866{
1867 wxPropertyGrid* pg = GetGrid();
1868 wxASSERT(pg);
1869
1870 wxPGProperty* selected = pg->GetSelection();
1871 if ( this == selected )
1872 {
1873 pg->DoSelectProperty(this, wxPG_SEL_FORCE);
1874 return true;
1875 }
1876 return false;
1877}
1878
1879
1880void wxPGProperty::SetValueImage( wxBitmap& bmp )
1881{
1882 delete m_valueBitmap;
1883
1884 if ( &bmp && bmp.Ok() )
1885 {
1886 // Resize the image
1887 wxSize maxSz = GetGrid()->GetImageSize();
1888 wxSize imSz(bmp.GetWidth(),bmp.GetHeight());
1889
1890 if ( imSz.x != maxSz.x || imSz.y != maxSz.y )
1891 {
1892 // Create a memory DC
1893 wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth());
1894
1895 wxMemoryDC dc;
1896 dc.SelectObject(*bmpNew);
1897
1898 // Scale
1899 // FIXME: This is ugly - use image or wait for scaling patch.
1900 double scaleX = (double)maxSz.x / (double)imSz.x;
1901 double scaleY = (double)maxSz.y / (double)imSz.y;
1902
1903 dc.SetUserScale(scaleX,scaleY);
1904
1905 dc.DrawBitmap( bmp, 0, 0 );
1906
1907 m_valueBitmap = bmpNew;
1908 }
1909 else
1910 {
1911 m_valueBitmap = new wxBitmap(bmp);
1912 }
1913
1914 m_flags |= wxPG_PROP_CUSTOMIMAGE;
1915 }
1916 else
1917 {
1918 m_valueBitmap = NULL;
1919 m_flags &= ~(wxPG_PROP_CUSTOMIMAGE);
1920 }
1921}
1922
1923
1924wxPGProperty* wxPGProperty::GetMainParent() const
1925{
1926 const wxPGProperty* curChild = this;
1927 const wxPGProperty* curParent = m_parent;
1928
1929 while ( curParent && !curParent->IsCategory() )
1930 {
1931 curChild = curParent;
1932 curParent = curParent->m_parent;
1933 }
1934
1935 return (wxPGProperty*) curChild;
1936}
1937
1938
1939const wxPGProperty* wxPGProperty::GetLastVisibleSubItem() const
1940{
1941 //
1942 // Returns last visible sub-item, recursively.
1943 if ( !IsExpanded() || !GetChildCount() )
1944 return this;
1945
1946 return Last()->GetLastVisibleSubItem();
1947}
1948
1949
1950bool wxPGProperty::IsVisible() const
1951{
1952 const wxPGProperty* parent;
1953
1954 if ( HasFlag(wxPG_PROP_HIDDEN) )
1955 return false;
1956
1957 for ( parent = GetParent(); parent != NULL; parent = parent->GetParent() )
1958 {
1959 if ( !parent->IsExpanded() || parent->HasFlag(wxPG_PROP_HIDDEN) )
1960 return false;
1961 }
1962
1963 return true;
1964}
1965
1966wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const
1967{
1968 wxPropertyGridPageState* state = GetParentState();
1969 wxPropertyGrid* propGrid = state->GetGrid();
1970 if ( state == propGrid->GetState() )
1971 return propGrid;
1972 return NULL;
1973}
1974
1975
1976int wxPGProperty::GetY2( int lh ) const
1977{
1978 const wxPGProperty* parent;
1979 const wxPGProperty* child = this;
1980
1981 int y = 0;
1982
1983 for ( parent = GetParent(); parent != NULL; parent = child->GetParent() )
1984 {
1985 if ( !parent->IsExpanded() )
1986 return -1;
1987 y += parent->GetChildrenHeight(lh, child->GetIndexInParent());
1988 y += lh;
1989 child = parent;
1990 }
1991
1992 y -= lh; // need to reduce one level
1993
1994 return y;
1995}
1996
1997
1998int wxPGProperty::GetY() const
1999{
2000 return GetY2(GetGrid()->GetRowHeight());
2001}
2002
1c4293cb
VZ
2003// This is used by Insert etc.
2004void wxPGProperty::AddChild2( wxPGProperty* prop, int index, bool correct_mode )
2005{
f7a094e1 2006 if ( index < 0 || (size_t)index >= m_children.size() )
1c4293cb 2007 {
f7a094e1
JS
2008 if ( correct_mode ) prop->m_arrIndex = m_children.size();
2009 m_children.push_back( prop );
1c4293cb
VZ
2010 }
2011 else
2012 {
f7a094e1 2013 m_children.insert( m_children.begin()+index, prop);
1b895132 2014 if ( correct_mode ) FixIndicesOfChildren( index );
1c4293cb
VZ
2015 }
2016
2017 prop->m_parent = this;
2018}
2019
2020// This is used by properties that have fixed sub-properties
2021void wxPGProperty::AddChild( wxPGProperty* prop )
2022{
d665918b
JS
2023 wxASSERT_MSG( prop->GetBaseName().length(),
2024 "Property's children must have unique, non-empty names within their scope" );
2025
f7a094e1
JS
2026 prop->m_arrIndex = m_children.size();
2027 m_children.push_back( prop );
1c4293cb
VZ
2028
2029 int custImgHeight = prop->OnMeasureImage().y;
2030 if ( custImgHeight < 0 /*|| custImgHeight > 1*/ )
2031 prop->m_flags |= wxPG_PROP_CUSTOMIMAGE;
2032
2033 prop->m_parent = this;
2034}
2035
d8c74d04
JS
2036void wxPGProperty::RemoveChild( wxPGProperty* p )
2037{
2038 wxArrayPGProperty::iterator it;
2039 wxArrayPGProperty& children = m_children;
2040
2041 for ( it=children.begin(); it != children.end(); it++ )
2042 {
2043 if ( *it == p )
2044 {
2045 m_children.erase(it);
2046 break;
2047 }
2048 }
2049}
1c4293cb
VZ
2050
2051void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const
2052{
2053 wxASSERT( GetChildCount() );
2054 wxASSERT( !IsCategory() );
2055
2056 *value = GetValue();
2057
2058 if ( !list.GetCount() )
2059 return;
2060
2061 wxASSERT( GetChildCount() >= (unsigned int)list.GetCount() );
2062
2063 bool allChildrenSpecified;
2064
2065 // Don't fully update aggregate properties unless all children have
2066 // specified value
2067 if ( HasFlag(wxPG_PROP_AGGREGATE) )
2068 allChildrenSpecified = AreAllChildrenSpecified(&list);
2069 else
2070 allChildrenSpecified = true;
2071
2072 wxVariant childValue = list[0];
2073 unsigned int i;
2074 unsigned int n = 0;
2075
d665918b 2076 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
1c4293cb
VZ
2077
2078 for ( i=0; i<GetChildCount(); i++ )
2079 {
2080 const wxPGProperty* child = Item(i);
2081
d665918b 2082 if ( childValue.GetName() == child->GetBaseName() )
1c4293cb
VZ
2083 {
2084 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2085
0372d42e 2086 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2087 {
2088 wxVariant cv2(child->GetValue());
2089 child->AdaptListToValue(childValue, &cv2);
2090 childValue = cv2;
2091 }
2092
2093 if ( allChildrenSpecified )
2094 ChildChanged(*value, i, childValue);
2095 n++;
2096 if ( n == (unsigned int)list.GetCount() )
2097 break;
2098 childValue = list[n];
2099 }
2100 }
2101}
2102
2103
1b895132 2104void wxPGProperty::FixIndicesOfChildren( unsigned int starthere )
1c4293cb
VZ
2105{
2106 size_t i;
2107 for ( i=starthere;i<GetChildCount();i++)
2108 Item(i)->m_arrIndex = i;
2109}
2110
2111
2112// Returns (direct) child property with given name (or NULL if not found)
2113wxPGProperty* wxPGProperty::GetPropertyByName( const wxString& name ) const
2114{
2115 size_t i;
2116
2117 for ( i=0; i<GetChildCount(); i++ )
2118 {
2119 wxPGProperty* p = Item(i);
2120 if ( p->m_name == name )
2121 return p;
2122 }
2123
2124 // Does it have point, then?
2125 int pos = name.Find(wxS('.'));
2126 if ( pos <= 0 )
2127 return (wxPGProperty*) NULL;
2128
2129 wxPGProperty* p = GetPropertyByName(name. substr(0,pos));
2130
2131 if ( !p || !p->GetChildCount() )
2132 return NULL;
2133
2134 return p->GetPropertyByName(name.substr(pos+1,name.length()-pos-1));
2135}
2136
d665918b 2137wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const
1c4293cb
VZ
2138{
2139 unsigned int i = hintIndex;
2140
2141 if ( i >= GetChildCount() )
2142 i = 0;
2143
2144 unsigned int lastIndex = i - 1;
2145
2146 if ( lastIndex >= GetChildCount() )
2147 lastIndex = GetChildCount() - 1;
2148
2149 for (;;)
2150 {
2151 wxPGProperty* p = Item(i);
d665918b 2152 if ( p->m_name == name )
1c4293cb
VZ
2153 return p;
2154
2155 if ( i == lastIndex )
2156 break;
2157
2158 i++;
2159 if ( i == GetChildCount() )
2160 i = 0;
2161 };
2162
2163 return NULL;
2164}
2165
2166int wxPGProperty::GetChildrenHeight( int lh, int iMax_ ) const
2167{
2168 // Returns height of children, recursively, and
2169 // by taking expanded/collapsed status into account.
2170 //
2171 // iMax is used when finding property y-positions.
2172 //
2173 unsigned int i = 0;
2174 int h = 0;
2175
2176 if ( iMax_ == -1 )
2177 iMax_ = GetChildCount();
2178
2179 unsigned int iMax = iMax_;
2180
2181 wxASSERT( iMax <= GetChildCount() );
2182
2183 if ( !IsExpanded() && GetParent() )
2184 return 0;
2185
2186 while ( i < iMax )
2187 {
2188 wxPGProperty* pwc = (wxPGProperty*) Item(i);
2189
2190 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2191 {
2192 if ( !pwc->IsExpanded() ||
2193 pwc->GetChildCount() == 0 )
2194 h += lh;
2195 else
2196 h += pwc->GetChildrenHeight(lh) + lh;
2197 }
2198
2199 i++;
2200 }
2201
2202 return h;
2203}
2204
2205wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y, unsigned int lh, unsigned int* nextItemY ) const
2206{
2207 wxASSERT( nextItemY );
2208
2209 // Linear search at the moment
2210 //
2211 // nextItemY = y of next visible property, final value will be written back.
2212 wxPGProperty* result = NULL;
2213 wxPGProperty* current = NULL;
2214 unsigned int iy = *nextItemY;
2215 unsigned int i = 0;
2216 unsigned int iMax = GetChildCount();
2217
2218 while ( i < iMax )
2219 {
2220 wxPGProperty* pwc = Item(i);
2221
2222 if ( !pwc->HasFlag(wxPG_PROP_HIDDEN) )
2223 {
2224 // Found?
2225 if ( y < iy )
2226 {
2227 result = current;
2228 break;
2229 }
2230
2231 iy += lh;
2232
2233 if ( pwc->IsExpanded() &&
2234 pwc->GetChildCount() > 0 )
2235 {
2236 result = (wxPGProperty*) pwc->GetItemAtY( y, lh, &iy );
2237 if ( result )
2238 break;
2239 }
2240
2241 current = pwc;
2242 }
2243
2244 i++;
2245 }
2246
2247 // Found?
2248 if ( !result && y < iy )
2249 result = current;
2250
2251 *nextItemY = iy;
2252
2253 /*
2254 if ( current )
2255 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
2256 else
2257 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
2258 */
2259
2260 return (wxPGProperty*) result;
2261}
2262
2263void wxPGProperty::Empty()
2264{
2265 size_t i;
2266 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES) )
2267 {
2268 for ( i=0; i<GetChildCount(); i++ )
2269 {
f7a094e1 2270 delete m_children[i];
1c4293cb
VZ
2271 }
2272 }
2273
f7a094e1 2274 m_children.clear();
1c4293cb
VZ
2275}
2276
2277void wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
2278 int WXUNUSED(childIndex),
2279 wxVariant& WXUNUSED(childValue) ) const
2280{
2281}
2282
2283bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const
2284{
2285 unsigned int i;
2286
2287 const wxVariantList* pList = NULL;
2288 wxVariantList::const_iterator node;
2289
2290 if ( pendingList )
2291 {
2292 pList = &pendingList->GetList();
2293 node = pList->begin();
2294 }
2295
1c4293cb
VZ
2296 for ( i=0; i<GetChildCount(); i++ )
2297 {
2298 wxPGProperty* child = Item(i);
2299 const wxVariant* listValue = NULL;
2300 wxVariant value;
2301
2302 if ( pendingList )
2303 {
d665918b 2304 const wxString& childName = child->GetBaseName();
1c4293cb 2305
b7bc9d80 2306 for ( ; node != pList->end(); ++node )
1c4293cb
VZ
2307 {
2308 const wxVariant& item = *((const wxVariant*)*node);
d665918b 2309 if ( item.GetName() == childName )
1c4293cb
VZ
2310 {
2311 listValue = &item;
2312 value = item;
2313 break;
2314 }
2315 }
2316 }
2317
2318 if ( !listValue )
2319 value = child->GetValue();
2320
2321 if ( value.IsNull() )
2322 return false;
2323
2324 // Check recursively
2325 if ( child->GetChildCount() )
2326 {
2327 const wxVariant* childList = NULL;
2328
0372d42e 2329 if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2330 childList = listValue;
2331
2332 if ( !child->AreAllChildrenSpecified((wxVariant*)childList) )
2333 return false;
2334 }
2335 }
2336
2337 return true;
2338}
2339
2340wxPGProperty* wxPGProperty::UpdateParentValues()
2341{
2342 wxPGProperty* parent = m_parent;
2343 if ( parent && parent->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
2344 !parent->IsCategory() && !parent->IsRoot() )
2345 {
2346 wxString s;
c82a80e8 2347 parent->DoGenerateComposedValue(s);
1c4293cb
VZ
2348 parent->m_value = s;
2349 return parent->UpdateParentValues();
2350 }
2351 return this;
2352}
2353
2354bool wxPGProperty::IsTextEditable() const
2355{
2356 if ( HasFlag(wxPG_PROP_READONLY) )
2357 return false;
2358
2359 if ( HasFlag(wxPG_PROP_NOEDITOR) &&
2360 (GetChildCount() ||
2361 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2362 )
2363 return false;
2364
2365 return true;
2366}
2367
1c4293cb
VZ
2368// Call after fixed sub-properties added/removed after creation.
2369// if oldSelInd >= 0 and < new max items, then selection is
2370// moved to it. Note: oldSelInd -2 indicates that this property
2371// should be selected.
2372void wxPGProperty::SubPropsChanged( int oldSelInd )
2373{
2374 wxPropertyGridPageState* state = GetParentState();
2375 wxPropertyGrid* grid = state->GetGrid();
2376
2fd4a524
JS
2377 //
2378 // Re-repare children (recursively)
2379 for ( unsigned int i=0; i<GetChildCount(); i++ )
2380 {
2381 wxPGProperty* child = Item(i);
2382 child->InitAfterAdded(state, grid);
2383 }
1c4293cb
VZ
2384
2385 wxPGProperty* sel = (wxPGProperty*) NULL;
f7a094e1
JS
2386 if ( oldSelInd >= (int)m_children.size() )
2387 oldSelInd = (int)m_children.size() - 1;
1c4293cb
VZ
2388
2389 if ( oldSelInd >= 0 )
f7a094e1 2390 sel = m_children[oldSelInd];
1c4293cb
VZ
2391 else if ( oldSelInd == -2 )
2392 sel = this;
2393
2394 if ( sel )
2395 state->DoSelectProperty(sel);
2396
2397 if ( state == grid->GetState() )
2398 {
2399 grid->GetPanel()->Refresh();
2400 }
2401}
2402
2403// -----------------------------------------------------------------------
2404// wxPGRootProperty
2405// -----------------------------------------------------------------------
2406
2407WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2408IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2409
2410
2411wxPGRootProperty::wxPGRootProperty()
2412 : wxPGProperty()
2413{
2414#ifdef __WXDEBUG__
2415 m_name = wxS("<root>");
2416#endif
2417 SetParentalType(0);
2418 m_depth = 0;
2419}
2420
2421
2422wxPGRootProperty::~wxPGRootProperty()
2423{
2424}
2425
2426
2427// -----------------------------------------------------------------------
2428// wxPropertyCategory
2429// -----------------------------------------------------------------------
2430
2431WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2432IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2433
2434void wxPropertyCategory::Init()
2435{
2436 // don't set colour - prepareadditem method should do this
2437 SetParentalType(wxPG_PROP_CATEGORY);
2438 m_capFgColIndex = 1;
2439 m_textExtent = -1;
2440}
2441
2442wxPropertyCategory::wxPropertyCategory()
2443 : wxPGProperty()
2444{
2445 Init();
2446}
2447
2448
2449wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2450 : wxPGProperty(label,name)
2451{
2452 Init();
2453}
2454
2455
2456wxPropertyCategory::~wxPropertyCategory()
2457{
2458}
2459
2460
1425eca5
JS
2461wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value),
2462 int WXUNUSED(argFlags) ) const
1c4293cb
VZ
2463{
2464 return wxEmptyString;
2465}
2466
2467int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const
2468{
2469 if ( m_textExtent > 0 )
2470 return m_textExtent;
2471 int x = 0, y = 0;
2472 ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2473 return x;
2474}
2475
2476void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font )
2477{
2478 int x = 0, y = 0;
2479 wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font );
2480 m_textExtent = x;
2481}
2482
2483// -----------------------------------------------------------------------
2484// wxPGAttributeStorage
2485// -----------------------------------------------------------------------
2486
2487wxPGAttributeStorage::wxPGAttributeStorage()
2488{
2489}
2490
2491wxPGAttributeStorage::~wxPGAttributeStorage()
2492{
2493 wxPGHashMapS2P::iterator it;
2494
b7bc9d80 2495 for ( it = m_map.begin(); it != m_map.end(); ++it )
1c4293cb
VZ
2496 {
2497 wxVariantData* data = (wxVariantData*) it->second;
2498 data->DecRef();
2499 }
2500}
2501
2502void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value )
2503{
2504 wxVariantData* data = value.GetData();
2505
2506 // Free old, if any
2507 wxPGHashMapS2P::iterator it = m_map.find(name);
2508 if ( it != m_map.end() )
1802a91d 2509 {
1c4293cb
VZ
2510 ((wxVariantData*)it->second)->DecRef();
2511
1802a91d
JS
2512 if ( !data )
2513 {
2514 // If Null variant, just remove from set
2515 m_map.erase(it);
2516 return;
2517 }
2518 }
2519
1c4293cb 2520 if ( data )
1802a91d 2521 {
1c4293cb
VZ
2522 data->IncRef();
2523
1802a91d
JS
2524 m_map[name] = data;
2525 }
1c4293cb
VZ
2526}
2527
f4bc1aa2 2528#endif // wxUSE_PROPGRID