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