When wxPGProperty is un-attached from wxPropertyGrid, keep its 'default' cell referen...
[wxWidgets.git] / src / propgrid / property.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/property.cpp
3 // Purpose: wxPGProperty and related support classes
4 // Author: Jaakko Salli
5 // Modified by:
6 // Created: 2008-08-23
7 // RCS-ID: $Id$
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows 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
49 const char* g_invalidStringContent = "@__TOTALLY_INVALID_STRING__@";
50
51 #endif
52
53 // -----------------------------------------------------------------------
54
55 static 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
87 wxSize wxPGCellRenderer::GetImageSize( const wxPGProperty* WXUNUSED(property),
88 int WXUNUSED(column),
89 int WXUNUSED(item) ) const
90 {
91 return wxSize(0, 0);
92 }
93
94 void 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
102 void 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
125 void 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
131 int 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
174 void 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
189 bool 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.length() )
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.length() )
262 text = wxString::Format(wxS("%s %s"), text.c_str(), unitsString.c_str() );
263 }
264 }
265
266 if ( text.length() == 0 )
267 {
268 text = property->GetHintText();
269 if ( text.length() > 0 )
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
318 wxSize 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
339 wxPGCellData::wxPGCellData()
340 : wxObjectRefData()
341 {
342 m_hasValidText = false;
343 }
344
345 // -----------------------------------------------------------------------
346 // wxPGCell
347 // -----------------------------------------------------------------------
348
349 wxPGCell::wxPGCell()
350 : wxObject()
351 {
352 }
353
354 wxPGCell::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
369 wxObjectRefData *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
381 void wxPGCell::SetText( const wxString& text )
382 {
383 AllocExclusive();
384
385 GetData()->SetText(text);
386 }
387
388 void wxPGCell::SetBitmap( const wxBitmap& bitmap )
389 {
390 AllocExclusive();
391
392 GetData()->SetBitmap(bitmap);
393 }
394
395 void wxPGCell::SetFgCol( const wxColour& col )
396 {
397 AllocExclusive();
398
399 GetData()->SetFgCol(col);
400 }
401
402 void wxPGCell::SetFont( const wxFont& font )
403 {
404 AllocExclusive();
405
406 GetData()->SetFont(font);
407 }
408
409 void wxPGCell::SetBgCol( const wxColour& col )
410 {
411 AllocExclusive();
412
413 GetData()->SetBgCol(col);
414 }
415
416 void 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
435 void wxPGCell::SetEmptyData()
436 {
437 AllocExclusive();
438 }
439
440
441 // -----------------------------------------------------------------------
442 // wxPGProperty
443 // -----------------------------------------------------------------------
444
445 IMPLEMENT_ABSTRACT_CLASS(wxPGProperty, wxObject)
446
447 wxString* wxPGProperty::sm_wxPG_LABEL = NULL;
448
449 void 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
476 void 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
492 void 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
641 void 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
662 wxPGProperty::wxPGProperty()
663 : wxObject()
664 {
665 Init();
666 }
667
668
669 wxPGProperty::wxPGProperty( const wxString& label, const wxString& name )
670 : wxObject()
671 {
672 Init( label, name );
673 }
674
675
676 wxPGProperty::~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
692 bool 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
704 void 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
714 wxString wxPGProperty::GetName() const
715 {
716 wxPGProperty* parent = GetParent();
717
718 if ( !m_name.length() || !parent || parent->IsCategory() || parent->IsRoot() )
719 return m_name;
720
721 return m_parent->GetName() + wxS(".") + m_name;
722 }
723
724 wxPropertyGrid* wxPGProperty::GetGrid() const
725 {
726 if ( !m_parentState )
727 return NULL;
728 return m_parentState->GetGrid();
729 }
730
731 int wxPGProperty::Index( const wxPGProperty* p ) const
732 {
733 return wxPGFindInVector(m_children, p);
734 }
735
736 bool wxPGProperty::ValidateValue( wxVariant& WXUNUSED(value), wxPGValidationInfo& WXUNUSED(validationInfo) ) const
737 {
738 return true;
739 }
740
741 void wxPGProperty::OnSetValue()
742 {
743 }
744
745 void wxPGProperty::RefreshChildren ()
746 {
747 }
748
749 void wxPGProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) )
750 {
751 }
752
753 void 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 /*
814 wxString 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
844 void 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.length() )
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
963 wxString 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
981 wxString 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
1023 wxString wxPGProperty::GetValueString( int argFlags ) const
1024 {
1025 return GetValueAsString(argFlags);
1026 }
1027
1028 bool 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.
1035 bool 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.length() )
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
1245 bool 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
1254 bool 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
1263 wxSize 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
1271 int 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
1287 wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const
1288 {
1289 return wxPGGlobalVars->m_defaultRenderer;
1290 }
1291
1292 void 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
1305 const wxPGEditor* wxPGProperty::DoGetEditorClass() const
1306 {
1307 return wxPGEditor_TextCtrl;
1308 }
1309
1310 // Default extra property event handling - that is, none at all.
1311 bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& )
1312 {
1313 return false;
1314 }
1315
1316
1317 void 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
1466 void wxPGProperty::SetValueInEvent( wxVariant value ) const
1467 {
1468 GetGrid()->ValueChangeInEvent(value);
1469 }
1470
1471 void 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
1480 void 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
1490 wxVariant 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
1533 void 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
1545 void 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
1558 void 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
1586 void wxPGProperty::SetCell( int column,
1587 const wxPGCell& cell )
1588 {
1589 EnsureCells(column);
1590
1591 m_cells[column] = cell;
1592 }
1593
1594 void 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
1641 const 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
1654 wxPGCell& wxPGProperty::GetOrCreateCell( unsigned int column )
1655 {
1656 EnsureCells(column);
1657 return m_cells[column];
1658 }
1659
1660 void 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
1696 void 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
1732 wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const
1733 {
1734 return NULL;
1735 }
1736
1737 bool wxPGProperty::DoSetAttribute( const wxString& WXUNUSED(name), wxVariant& WXUNUSED(value) )
1738 {
1739 return false;
1740 }
1741
1742 void 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
1754 void 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
1763 wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
1764 {
1765 return wxVariant();
1766 }
1767
1768
1769 wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
1770 {
1771 return m_attributes.FindValue(name);
1772 }
1773
1774 wxString 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
1784 long 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
1794 double 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
1804 wxVariant 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
1819 const unsigned int gs_propFlagToStringSize = 14;
1820
1821 static 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
1838 wxString 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.length() )
1852 s << wxS("|");
1853 s << fs;
1854 }
1855 a = a << 1;
1856 }
1857
1858 return s;
1859 }
1860
1861 void 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
1881 wxValidator* wxPGProperty::DoGetValidator() const
1882 {
1883 return NULL;
1884 }
1885
1886 int 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
1911 void 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
1938 int 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
1963 void 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
1981 bool 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
2005 const 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
2032 bool 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
2041 bool 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
2058 bool 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
2073 bool 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
2088 void 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
2131 wxPGProperty* 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
2146 const 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
2157 bool 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
2173 wxPropertyGrid* 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
2185 int 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
2207 int wxPGProperty::GetY() const
2208 {
2209 return GetY2(GetGrid()->GetRowHeight());
2210 }
2211
2212 // This is used by Insert etc.
2213 void 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
2230 void 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
2247 void 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
2261 void wxPGProperty::AddChild( wxPGProperty* prop )
2262 {
2263 AddPrivateChild(prop);
2264 }
2265 #endif
2266
2267 wxPGProperty* 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
2293 void 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
2308 void 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 wxVariant childValue = list[0];
2330 unsigned int i;
2331 unsigned int n = 0;
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
2364 void 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)
2373 wxPGProperty* 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
2397 wxPGProperty* 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
2426 int 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
2465 wxPGProperty* 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
2529 void 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
2543 wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y ) const
2544 {
2545 unsigned int nextItem;
2546 return GetItemAtY( y, GetGrid()->GetRowHeight(), &nextItem);
2547 }
2548
2549 void 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
2566 wxVariant wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
2567 int WXUNUSED(childIndex),
2568 wxVariant& WXUNUSED(childValue) ) const
2569 {
2570 return wxNullVariant;
2571 }
2572
2573 bool 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
2630 wxPGProperty* 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
2644 bool 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.
2662 void 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
2697 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2698 IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2699
2700
2701 wxPGRootProperty::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
2711 wxPGRootProperty::~wxPGRootProperty()
2712 {
2713 }
2714
2715
2716 // -----------------------------------------------------------------------
2717 // wxPropertyCategory
2718 // -----------------------------------------------------------------------
2719
2720 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2721 IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2722
2723 void 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
2731 wxPropertyCategory::wxPropertyCategory()
2732 : wxPGProperty()
2733 {
2734 Init();
2735 }
2736
2737
2738 wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2739 : wxPGProperty(label,name)
2740 {
2741 Init();
2742 }
2743
2744
2745 wxPropertyCategory::~wxPropertyCategory()
2746 {
2747 }
2748
2749
2750 wxString 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
2758 wxString 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
2778 int 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
2787 void 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
2798 wxPGChoiceEntry& 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
2808 wxPGChoiceEntry& 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
2819 wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index )
2820 {
2821 AllocExclusive();
2822
2823 return m_data->Insert( index, entry );
2824 }
2825
2826 // -----------------------------------------------------------------------
2827
2828 wxPGChoiceEntry& 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
2838 wxPGChoiceEntry& 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
2858 void 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
2879 void 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
2898 void 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
2909 void wxPGChoices::Clear()
2910 {
2911 if ( m_data != wxPGChoicesEmptyData )
2912 {
2913 AllocExclusive();
2914 m_data->Clear();
2915 }
2916 }
2917
2918 // -----------------------------------------------------------------------
2919
2920 int 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
2937 int 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
2954 wxArrayString 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
2968 wxArrayInt 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
2990 wxArrayInt 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
3014 void 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
3029 void 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
3042 void wxPGChoices::Init()
3043 {
3044 m_data = wxPGChoicesEmptyData;
3045 }
3046
3047 // -----------------------------------------------------------------------
3048
3049 void 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
3062 wxPGAttributeStorage::wxPGAttributeStorage()
3063 {
3064 }
3065
3066 wxPGAttributeStorage::~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
3077 void 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