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