]> git.saurik.com Git - wxWidgets.git/blame - src/propgrid/property.cpp
Fix wxHtmlHelpData::SetTempDir() to behave correctly without trailing slash.
[wxWidgets.git] / src / propgrid / property.cpp
CommitLineData
1c4293cb
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/propgrid/property.cpp
3// Purpose: wxPGProperty and related support classes
4// Author: Jaakko Salli
5// Modified by:
6// Created: 2008-08-23
1c4293cb 7// Copyright: (c) Jaakko Salli
526954c5 8// Licence: wxWindows licence
1c4293cb
VZ
9/////////////////////////////////////////////////////////////////////////////
10
11// For compilers that support precompilation, includes "wx/wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
f4bc1aa2
JS
18#if wxUSE_PROPGRID
19
1c4293cb
VZ
20#ifndef WX_PRECOMP
21 #include "wx/defs.h"
22 #include "wx/object.h"
23 #include "wx/hash.h"
24 #include "wx/string.h"
25 #include "wx/log.h"
026f3f9b 26 #include "wx/math.h"
1c4293cb
VZ
27 #include "wx/event.h"
28 #include "wx/window.h"
29 #include "wx/panel.h"
30 #include "wx/dc.h"
31 #include "wx/dcmemory.h"
1c4293cb
VZ
32 #include "wx/pen.h"
33 #include "wx/brush.h"
1c4293cb 34 #include "wx/settings.h"
1c4293cb 35 #include "wx/intl.h"
1c4293cb
VZ
36#endif
37
0429e043
JS
38#include "wx/image.h"
39
3b211af1 40#include "wx/propgrid/propgrid.h"
1c4293cb
VZ
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
1425eca5
JS
48#if wxPG_COMPATIBILITY_1_4
49
f3323039 50// Used to establish backwards compatibility
1425eca5
JS
51const char* g_invalidStringContent = "@__TOTALLY_INVALID_STRING__@";
52
53#endif
1c4293cb
VZ
54
55// -----------------------------------------------------------------------
56
57static 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
89wxSize wxPGCellRenderer::GetImageSize( const wxPGProperty* WXUNUSED(property),
90 int WXUNUSED(column),
91 int WXUNUSED(item) ) const
92{
93 return wxSize(0, 0);
94}
95
96void wxPGCellRenderer::DrawText( wxDC& dc, const wxRect& rect,
97 int xOffset, const wxString& text ) const
98{
1c4293cb
VZ
99 dc.DrawText( text,
100 rect.x+xOffset+wxPG_XBEFORETEXT,
101 rect.y+((rect.height-dc.GetCharHeight())/2) );
102}
103
104void wxPGCellRenderer::DrawEditorValue( wxDC& dc, const wxRect& rect,
105 int xOffset, const wxString& text,
106 wxPGProperty* property,
107 const wxPGEditor* editor ) const
108{
1c4293cb
VZ
109 int yOffset = ((rect.height-dc.GetCharHeight())/2);
110
111 if ( editor )
112 {
03647350 113 wxRect rect2(rect);
1c4293cb
VZ
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
127void 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
133int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& cell, int flags ) const
134{
4aee8334 135 int imageWidth = 0;
1c4293cb 136
d7e2b522
JS
137 // If possible, use cell colours
138 if ( !(flags & DontUseCellBgCol) )
1c4293cb 139 {
3e6d8c31
JS
140 const wxColour& bgCol = cell.GetBgCol();
141 dc.SetPen(bgCol);
142 dc.SetBrush(bgCol);
d7e2b522 143 }
1c4293cb 144
d7e2b522
JS
145 if ( !(flags & DontUseCellFgCol) )
146 {
147 dc.SetTextForeground(cell.GetFgCol());
1c4293cb
VZ
148 }
149
a2851207
JS
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);
d7e2b522 154
aaf5f986
JS
155 // Use cell font, if provided
156 const wxFont& font = cell.GetFont();
157 if ( font.IsOk() )
158 dc.SetFont(font);
159
1c4293cb 160 const wxBitmap& bmp = cell.GetBitmap();
a1b806b9 161 if ( bmp.IsOk() &&
d7e2b522
JS
162 // Do not draw oversized bitmap outside choice popup
163 ((flags & ChoicePopup) || bmp.GetHeight() < rect.height )
1c4293cb
VZ
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 );
4aee8334 170 imageWidth = bmp.GetWidth();
1c4293cb
VZ
171 }
172
4aee8334 173 return imageWidth;
1c4293cb
VZ
174}
175
aaf5f986
JS
176void 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
1c4293cb
VZ
187// -----------------------------------------------------------------------
188// wxPGDefaultRenderer
189// -----------------------------------------------------------------------
190
e16bff8e 191bool wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect,
1c4293cb
VZ
192 const wxPropertyGrid* propertyGrid, wxPGProperty* property,
193 int column, int item, int flags ) const
194{
e16bff8e
JS
195 const wxPGEditor* editor = NULL;
196 const wxPGCell* cell = NULL;
197
198 wxString text;
1c4293cb
VZ
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 )
e16bff8e
JS
208 {
209 text = propertyGrid->GetCommonValueLabel(cmnVal);
210 DrawText( dc, rect, 0, text );
6636ef8d 211 if ( !text.empty() )
e16bff8e
JS
212 return true;
213 }
214 return false;
1c4293cb
VZ
215 }
216 }
217
4aee8334 218 int imageWidth = 0;
d7e2b522 219 int preDrawFlags = flags;
e16bff8e 220 bool res = false;
1c4293cb 221
d7e2b522 222 property->GetDisplayInfo(column, item, flags, &text, &cell);
1c4293cb 223
4aee8334 224 imageWidth = PreDrawCell( dc, rect, *cell, preDrawFlags );
1c4293cb 225
d7e2b522 226 if ( column == 1 )
1c4293cb 227 {
5900bb7c
JS
228 editor = property->GetColumnEditor(column);
229
1c4293cb
VZ
230 if ( !isUnspecified )
231 {
1c4293cb
VZ
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
1c4293cb
VZ
247 dc.SetPen( wxPen(propertyGrid->GetCellTextColour(), 1, wxSOLID) );
248
249 paintdata.m_drawnWidth = imageSize.x;
250 paintdata.m_drawnHeight = imageSize.y;
251
b7bc9d80 252 property->OnCustomPaint( dc, imageRect, paintdata );
1c4293cb 253
4aee8334 254 imageWidth = paintdata.m_drawnWidth;
1c4293cb
VZ
255 }
256
1425eca5 257 text = property->GetValueAsString();
1c4293cb
VZ
258
259 // Add units string?
260 if ( propertyGrid->GetColumnCount() <= 2 )
261 {
262 wxString unitsString = property->GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
6636ef8d 263 if ( !unitsString.empty() )
1c4293cb
VZ
264 text = wxString::Format(wxS("%s %s"), text.c_str(), unitsString.c_str() );
265 }
266 }
267
6636ef8d 268 if ( text.empty() )
1c4293cb 269 {
534090e3 270 text = property->GetHintText();
6636ef8d 271 if ( !text.empty() )
1c4293cb 272 {
e16bff8e
JS
273 res = true;
274
534090e3
JS
275 const wxColour& hCol =
276 propertyGrid->GetCellDisabledTextColour();
277 dc.SetTextForeground(hCol);
01c22669 278
e3778b4d 279 // Must make the editor NULL to override its own rendering
01c22669
JS
280 // code.
281 editor = NULL;
1c4293cb
VZ
282 }
283 }
e16bff8e
JS
284 else
285 {
286 res = true;
287 }
1c4293cb 288 }
1c4293cb 289
4aee8334
JS
290 int imageOffset = property->GetImageOffset(imageWidth);
291
1c4293cb
VZ
292 DrawEditorValue( dc, rect, imageOffset, text, property, editor );
293
294 // active caption gets nice dotted rectangle
e16bff8e 295 if ( property->IsCategory() && column == 0 )
1c4293cb
VZ
296 {
297 if ( flags & Selected )
298 {
50355f75 299 if ( imageOffset > 0 )
4aee8334
JS
300 {
301 imageOffset -= DEFAULT_IMAGE_OFFSET_INCREMENT;
50355f75 302 imageOffset += wxCC_CUSTOM_IMAGE_MARGIN2 + 4;
4aee8334 303 }
1c4293cb
VZ
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 }
aaf5f986
JS
314
315 PostDrawCell(dc, propertyGrid, *cell, preDrawFlags);
e16bff8e
JS
316
317 return res;
1c4293cb
VZ
318}
319
320wxSize 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
a1b806b9 330 if ( bmp && bmp->IsOk() )
1c4293cb
VZ
331 return wxSize(bmp->GetWidth(),bmp->GetHeight());
332 }
333 }
334 return wxSize(0,0);
335}
336
d7e2b522
JS
337// -----------------------------------------------------------------------
338// wxPGCellData
339// -----------------------------------------------------------------------
340
341wxPGCellData::wxPGCellData()
342 : wxObjectRefData()
343{
344 m_hasValidText = false;
345}
346
1c4293cb
VZ
347// -----------------------------------------------------------------------
348// wxPGCell
349// -----------------------------------------------------------------------
350
351wxPGCell::wxPGCell()
d7e2b522 352 : wxObject()
1c4293cb
VZ
353{
354}
355
356wxPGCell::wxPGCell( const wxString& text,
357 const wxBitmap& bitmap,
358 const wxColour& fgCol,
359 const wxColour& bgCol )
d7e2b522
JS
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
371wxObjectRefData *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
383void wxPGCell::SetText( const wxString& text )
384{
385 AllocExclusive();
386
387 GetData()->SetText(text);
388}
389
390void wxPGCell::SetBitmap( const wxBitmap& bitmap )
1c4293cb 391{
d7e2b522
JS
392 AllocExclusive();
393
394 GetData()->SetBitmap(bitmap);
395}
396
397void wxPGCell::SetFgCol( const wxColour& col )
398{
399 AllocExclusive();
400
401 GetData()->SetFgCol(col);
402}
403
aaf5f986
JS
404void wxPGCell::SetFont( const wxFont& font )
405{
406 AllocExclusive();
407
408 GetData()->SetFont(font);
409}
410
d7e2b522
JS
411void wxPGCell::SetBgCol( const wxColour& col )
412{
413 AllocExclusive();
414
415 GetData()->SetBgCol(col);
416}
417
418void 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());
1c4293cb
VZ
435}
436
3e6d8c31
JS
437void wxPGCell::SetEmptyData()
438{
439 AllocExclusive();
440}
441
442
1c4293cb
VZ
443// -----------------------------------------------------------------------
444// wxPGProperty
445// -----------------------------------------------------------------------
446
447IMPLEMENT_ABSTRACT_CLASS(wxPGProperty, wxObject)
448
449wxString* wxPGProperty::sm_wxPG_LABEL = NULL;
450
451void wxPGProperty::Init()
452{
453 m_commonValue = -1;
454 m_arrIndex = 0xFFFF;
455 m_parent = NULL;
456
d3b9f782 457 m_parentState = NULL;
1c4293cb
VZ
458
459 m_clientData = NULL;
460 m_clientObject = NULL;
461
d3b9f782 462 m_customEditor = NULL;
1c4293cb 463#if wxUSE_VALIDATORS
d3b9f782 464 m_validator = NULL;
1c4293cb 465#endif
d3b9f782 466 m_valueBitmap = NULL;
1c4293cb
VZ
467
468 m_maxLen = 0; // infinite maximum length
469
470 m_flags = wxPG_PROP_PROPERTY;
471
472 m_depth = 1;
1c4293cb
VZ
473
474 SetExpanded(true);
475}
476
477
478void 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
2fd4a524
JS
494void 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;
80a46597 502 bool parentIsRoot = parent->IsKindOf(wxCLASSINFO(wxPGRootProperty));
2fd4a524 503
ed8b46bb
JS
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
2fd4a524
JS
521 m_parentState = pageState;
522
1425eca5
JS
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
d7e2b522 530 if ( !parentIsRoot && !parent->IsCategory() )
2fd4a524 531 {
d7e2b522 532 m_cells = parent->m_cells;
2fd4a524
JS
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 {
2fd4a524 610 // Check parental flags
48a32cf6
JS
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" );
2fd4a524
JS
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
ed8b46bb
JS
643void 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
1c4293cb
VZ
664wxPGProperty::wxPGProperty()
665 : wxObject()
666{
667 Init();
668}
669
670
671wxPGProperty::wxPGProperty( const wxString& label, const wxString& name )
672 : wxObject()
673{
674 Init( label, name );
675}
676
677
678wxPGProperty::~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
1c4293cb
VZ
689 // This makes it easier for us to detect dangling pointers
690 m_parent = NULL;
691}
692
693
694bool 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
5fdb6350
JS
706void 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}
1c4293cb
VZ
715
716wxString wxPGProperty::GetName() const
717{
718 wxPGProperty* parent = GetParent();
719
6636ef8d 720 if ( m_name.empty() || !parent || parent->IsCategory() || parent->IsRoot() )
1c4293cb
VZ
721 return m_name;
722
723 return m_parent->GetName() + wxS(".") + m_name;
724}
725
726wxPropertyGrid* wxPGProperty::GetGrid() const
727{
728 if ( !m_parentState )
729 return NULL;
730 return m_parentState->GetGrid();
731}
732
f7a094e1
JS
733int wxPGProperty::Index( const wxPGProperty* p ) const
734{
8d2c7041 735 return wxPGFindInVector(m_children, p);
f7a094e1 736}
1c4293cb 737
1c4293cb
VZ
738bool wxPGProperty::ValidateValue( wxVariant& WXUNUSED(value), wxPGValidationInfo& WXUNUSED(validationInfo) ) const
739{
740 return true;
741}
742
743void wxPGProperty::OnSetValue()
744{
745}
746
747void wxPGProperty::RefreshChildren ()
748{
749}
750
d8812c6e
JS
751void wxPGProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) )
752{
753}
754
d7e2b522
JS
755void 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 {
3e6d8c31
JS
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
d7e2b522
JS
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/*
816wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
1c4293cb 817{
03647350 818
d7e2b522 819 if ( col != 1 || choiceIndex == wxNOT_FOUND )
1c4293cb 820 {
d7e2b522
JS
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 }
1c4293cb
VZ
835 }
836 else
837 {
d7e2b522
JS
838 // Use choice
839 return m_choices.GetLabel(choiceIndex);
1c4293cb
VZ
840 }
841
842 return wxEmptyString;
843}
d7e2b522 844*/
1c4293cb 845
c82a80e8
JS
846void wxPGProperty::DoGenerateComposedValue( wxString& text,
847 int argFlags,
848 const wxVariantList* valueOverrides,
849 wxPGHashMapS2S* childResults ) const
1c4293cb
VZ
850{
851 int i;
f7a094e1 852 int iMax = m_children.size();
1c4293cb
VZ
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
f7a094e1 867 wxPGProperty* curChild = m_children[0];
1c4293cb 868
1425eca5
JS
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
1c4293cb
VZ
883 for ( i = 0; i < iMax; i++ )
884 {
1425eca5
JS
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();
b7bc9d80 896 ++node;
1425eca5
JS
897 if ( node != valueOverrides->end() )
898 overrideValue = *node;
899 else
900 overridesLeft = false;
901 }
902 else
903 {
904 childValue = curChild->GetValue();
905 }
906
1c4293cb 907 wxString s;
1425eca5
JS
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();
c82a80e8
JS
915 DoGenerateComposedValue(s, argFlags|wxPG_COMPOSITE_FRAGMENT,
916 &childList, childResults);
1425eca5
JS
917 }
918 else
919 {
920 s = curChild->ValueToString(childValue,
921 argFlags|wxPG_COMPOSITE_FRAGMENT);
922 }
923 }
03647350 924
1425eca5
JS
925 if ( childResults && curChild->GetChildCount() )
926 (*childResults)[curChild->GetName()] = s;
1c4293cb
VZ
927
928 bool skip = false;
6636ef8d 929 if ( (argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT) && s.empty() )
1c4293cb
VZ
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
f7a094e1 952 curChild = m_children[i+1];
1c4293cb
VZ
953 }
954 }
955
f7a094e1 956 if ( (unsigned int)i < m_children.size() )
7036fd20
JS
957 {
958 if ( !text.EndsWith(wxS("; ")) )
959 text += wxS("; ...");
960 else
961 text += wxS("...");
962 }
1c4293cb
VZ
963}
964
1425eca5
JS
965wxString wxPGProperty::ValueToString( wxVariant& WXUNUSED(value),
966 int argFlags ) const
1c4293cb
VZ
967{
968 wxCHECK_MSG( GetChildCount() > 0,
969 wxString(),
1425eca5
JS
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." );
1c4293cb
VZ
977
978 wxString text;
c82a80e8 979 DoGenerateComposedValue(text, argFlags);
1c4293cb
VZ
980 return text;
981}
982
1425eca5 983wxString wxPGProperty::GetValueAsString( int argFlags ) const
1c4293cb 984{
1425eca5
JS
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
68174df3
JS
996 wxPropertyGrid* pg = GetGrid();
997
1c4293cb 998 if ( IsValueUnspecified() )
68174df3 999 return pg->GetUnspecifiedValueText(argFlags);
1c4293cb
VZ
1000
1001 if ( m_commonValue == -1 )
1425eca5
JS
1002 {
1003 wxVariant value(GetValue());
1004 return ValueToString(value, argFlags|wxPG_VALUE_IS_CURRENT);
1005 }
1c4293cb
VZ
1006
1007 //
1008 // Return common value's string representation
1c4293cb
VZ
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
1425eca5
JS
1025wxString wxPGProperty::GetValueString( int argFlags ) const
1026{
1027 return GetValueAsString(argFlags);
1028}
1029
1c4293cb
VZ
1030bool 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.
7d1214cd 1037bool wxPGProperty::StringToValue( wxVariant& v, const wxString& text, int argFlags ) const
1c4293cb
VZ
1038{
1039 if ( !GetChildCount() )
1040 return false;
1041
1042 unsigned int curChild = 0;
1043
f7a094e1 1044 unsigned int iMax = m_children.size();
1c4293cb
VZ
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
f275b5db 1064 int propagatedFlags = argFlags & (wxPG_REPORT_ERROR|wxPG_PROGRAMMATIC_VALUE);
1c4293cb 1065
4b6a582b
VZ
1066 wxLogTrace("propgrid",
1067 wxT(">> %s.StringToValue('%s')"), GetLabel(), text);
1c4293cb
VZ
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 {
a64a1bf7
JS
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
1c4293cb
VZ
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);
f275b5db 1096 wxVariant variant(child->GetValue());
ae82388e 1097 wxString childName = child->GetBaseName();
f275b5db 1098
4b6a582b
VZ
1099 wxLogTrace("propgrid",
1100 wxT("token = '%s', child = %s"),
1101 token, childName);
1c4293cb 1102
f275b5db
JS
1103 // Add only if editable or setting programmatically
1104 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
6cf5edea
JS
1105 (!child->HasFlag(wxPG_PROP_DISABLED) &&
1106 !child->HasFlag(wxPG_PROP_READONLY)) )
1c4293cb 1107 {
f275b5db 1108 if ( len > 0 )
1c4293cb 1109 {
ae82388e
JS
1110 if ( child->StringToValue(variant, token,
1111 propagatedFlags|wxPG_COMPOSITE_FRAGMENT) )
1c4293cb 1112 {
ae82388e
JS
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);
f275b5db 1122 list.Append(variant);
1c4293cb 1123
f275b5db
JS
1124 changed = true;
1125 }
1126 }
1127 else
1128 {
1129 // Empty, becomes unspecified
1130 variant.MakeNull();
ae82388e 1131 variant.SetName(childName);
f275b5db 1132 list.Append(variant);
1c4293cb
VZ
1133 changed = true;
1134 }
1135 }
1c4293cb
VZ
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
b7bc9d80 1158 if ( it != text.end() ) ++it;
1c4293cb
VZ
1159 pos++;
1160 size_t startPos = pos;
1161
1162 // Group item - find end
1163 while ( it != text.end() && depth > 0 )
1164 {
1165 a = *it;
b7bc9d80 1166 ++it;
1c4293cb
VZ
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
6636ef8d 1177 if ( token.empty() )
1c4293cb
VZ
1178 break;
1179
1180 const wxPGProperty* child = Item(curChild);
1181
2bbd3749
JS
1182 wxVariant oldChildValue = child->GetValue();
1183 wxVariant variant(oldChildValue);
f275b5db
JS
1184
1185 if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) ||
6cf5edea
JS
1186 (!child->HasFlag(wxPG_PROP_DISABLED) &&
1187 !child->HasFlag(wxPG_PROP_READONLY)) )
1c4293cb 1188 {
a64a1bf7
JS
1189 wxString childName = child->GetBaseName();
1190
1191 bool stvRes = child->StringToValue( variant, token,
1192 propagatedFlags );
f275b5db
JS
1193 if ( stvRes || (variant != oldChildValue) )
1194 {
a64a1bf7
JS
1195 variant.SetName(childName);
1196 list.Append(variant);
1197
1198 changed = true;
f275b5db
JS
1199 }
1200 else
1201 {
a64a1bf7 1202 // No changes...
f275b5db 1203 }
1c4293cb
VZ
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 )
a64a1bf7 1219 strPosIncrement -= 1;
1c4293cb
VZ
1220 }
1221 }
1222 }
1223
1224 if ( a == 0 )
1225 break;
1226
a64a1bf7
JS
1227 it += strPosIncrement;
1228
1c4293cb
VZ
1229 if ( it != text.end() )
1230 {
1231 a = *it;
1232 }
1233 else
1234 {
1235 a = 0;
1236 }
a64a1bf7
JS
1237
1238 pos += strPosIncrement;
1c4293cb
VZ
1239 }
1240
1241 if ( changed )
7d1214cd 1242 v = list;
1c4293cb
VZ
1243
1244 return changed;
1245}
1246
1247bool 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
1256bool 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
1265wxSize 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
4aee8334
JS
1273int 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
1c4293cb
VZ
1289wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const
1290{
1291 return wxPGGlobalVars->m_defaultRenderer;
1292}
1293
1294void wxPGProperty::OnCustomPaint( wxDC& dc,
1295 const wxRect& rect,
1296 wxPGPaintData& )
1297{
1298 wxBitmap* bmp = m_valueBitmap;
1299
a1b806b9 1300 wxCHECK_RET( bmp && bmp->IsOk(), wxT("invalid bitmap") );
1c4293cb
VZ
1301
1302 wxCHECK_RET( rect.x >= 0, wxT("unexpected measure call") );
1303
1304 dc.DrawBitmap(*bmp,rect.x,rect.y);
1305}
1306
1307const wxPGEditor* wxPGProperty::DoGetEditorClass() const
1308{
c26873c8 1309 return wxPGEditor_TextCtrl;
1c4293cb
VZ
1310}
1311
1312// Default extra property event handling - that is, none at all.
1313bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& )
1314{
1315 return false;
1316}
1317
1318
1319void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags )
1320{
104837f2
JS
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
1c4293cb
VZ
1329 if ( !value.IsNull() )
1330 {
8f18b252
JS
1331 wxVariant tempListVariant;
1332
1c4293cb
VZ
1333 SetCommonValue(-1);
1334 // List variants are reserved a special purpose
1335 // as intermediate containers for child values
1336 // of properties with children.
0372d42e 1337 if ( value.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb 1338 {
8f18b252
JS
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
1c4293cb
VZ
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 {
0372d42e 1358 wxASSERT( pList->GetType() == wxPG_VARIANT_TYPE_LIST );
1c4293cb
VZ
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
d665918b 1369 // GetPropertyByNameWH(). This optimizes for full list parsing.
b7bc9d80 1370 for ( node = list.begin(); node != list.end(); ++node )
1c4293cb
VZ
1371 {
1372 wxVariant& childValue = *((wxVariant*)*node);
d665918b 1373 wxPGProperty* child = GetPropertyByNameWH(childValue.GetName(), i);
1c4293cb
VZ
1374 if ( child )
1375 {
d665918b 1376 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
0372d42e 1377 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
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 }
0372d42e 1390 else if ( child->GetValue() != childValue )
1c4293cb
VZ
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);
8f18b252
JS
1396 if ( flags & wxPG_SETVAL_BY_USER )
1397 child->SetFlag(wxPG_PROP_MODIFIED);
1c4293cb
VZ
1398 }
1399 }
1400 i++;
1401 }
ace9bc26
JS
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();
1c4293cb
VZ
1408 }
1409
1410 if ( !value.IsNull() )
1411 {
0372d42e 1412 m_value = value;
1c4293cb 1413 OnSetValue();
1c4293cb
VZ
1414 }
1415
8f18b252 1416 if ( flags & wxPG_SETVAL_BY_USER )
1c4293cb
VZ
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
daeb4e4d
JS
1443 if ( !(flags & wxPG_SETVAL_FROM_PARENT) )
1444 UpdateParentValues();
1445
1c4293cb 1446 //
5ff90676 1447 // Update editor control.
1c4293cb 1448 if ( flags & wxPG_SETVAL_REFRESH_EDITOR )
e777bd14 1449 {
e777bd14
JS
1450 wxPropertyGrid* pg = GetGridIfDisplayed();
1451 if ( pg )
5ff90676
JS
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
e777bd14 1462 pg->DrawItemAndValueRelated(this);
5ff90676 1463 }
e777bd14 1464 }
1c4293cb
VZ
1465}
1466
1467
1468void wxPGProperty::SetValueInEvent( wxVariant value ) const
1469{
1470 GetGrid()->ValueChangeInEvent(value);
1471}
1472
6cf5edea 1473void wxPGProperty::SetFlagRecursively( wxPGPropertyFlags flag, bool set )
1c4293cb 1474{
d58526d5 1475 ChangeFlag(flag, set);
1c4293cb
VZ
1476
1477 unsigned int i;
1478 for ( i = 0; i < GetChildCount(); i++ )
1479 Item(i)->SetFlagRecursively(flag, set);
1480}
1481
1482void wxPGProperty::RefreshEditor()
1483{
f521bae6
JS
1484 if ( !m_parent )
1485 return;
1c4293cb 1486
f521bae6
JS
1487 wxPropertyGrid* pg = GetGrid();
1488 if ( pg && pg->GetSelectedProperty() == this )
a6353fe8 1489 pg->RefreshEditor();
f521bae6 1490}
1c4293cb
VZ
1491
1492wxVariant wxPGProperty::GetDefaultValue() const
1493{
0ce8e27f 1494 wxVariant defVal = GetAttribute(wxPG_ATTR_DEFAULT_VALUE);
1c4293cb
VZ
1495 if ( !defVal.IsNull() )
1496 return defVal;
1497
1498 wxVariant value = GetValue();
1499
1500 if ( !value.IsNull() )
1501 {
0372d42e
JS
1502 wxString valueType(value.GetType());
1503
1504 if ( valueType == wxPG_VARIANT_TYPE_LONG )
1c4293cb 1505 return wxPGVariant_Zero;
0372d42e 1506 if ( valueType == wxPG_VARIANT_TYPE_STRING )
1c4293cb 1507 return wxPGVariant_EmptyString;
0372d42e 1508 if ( valueType == wxPG_VARIANT_TYPE_BOOL )
1c4293cb 1509 return wxPGVariant_False;
0372d42e 1510 if ( valueType == wxPG_VARIANT_TYPE_DOUBLE )
1c4293cb 1511 return wxVariant(0.0);
0372d42e 1512 if ( valueType == wxPG_VARIANT_TYPE_ARRSTRING )
1c4293cb 1513 return wxVariant(wxArrayString());
0372d42e
JS
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);
1c4293cb 1520#if wxUSE_DATETIME
0372d42e 1521 if ( valueType == wxPG_VARIANT_TYPE_DATETIME )
1c4293cb
VZ
1522 return wxVariant(wxDateTime::Now());
1523#endif
0372d42e
JS
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));
1c4293cb
VZ
1530 }
1531
1532 return wxVariant();
1533}
1534
9ceed261
JS
1535void 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
1547void 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
d7e2b522
JS
1560void 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
ed8b46bb
JS
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();
521f1d83 1573
ed8b46bb
JS
1574 if ( !HasFlag(wxPG_PROP_CATEGORY) )
1575 defaultCell = propDefCell;
1576 else
1577 defaultCell = catDefCell;
1578 }
d7e2b522
JS
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
1588void wxPGProperty::SetCell( int column,
1589 const wxPGCell& cell )
1590{
1591 EnsureCells(column);
1592
1593 m_cells[column] = cell;
1594}
1595
1596void 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
1643const wxPGCell& wxPGProperty::GetCell( unsigned int column ) const
1c4293cb 1644{
d7e2b522
JS
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
58935d4a 1656wxPGCell& wxPGProperty::GetOrCreateCell( unsigned int column )
d7e2b522
JS
1657{
1658 EnsureCells(column);
1659 return m_cells[column];
1660}
1661
1662void wxPGProperty::SetBackgroundColour( const wxColour& colour,
e607eac2 1663 int flags )
d7e2b522
JS
1664{
1665 wxPGProperty* firstProp = this;
e607eac2 1666 bool recursively = flags & wxPG_RECURSE ? true : false;
d7e2b522
JS
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
1698void wxPGProperty::SetTextColour( const wxColour& colour,
e607eac2 1699 int flags )
d7e2b522
JS
1700{
1701 wxPGProperty* firstProp = this;
e607eac2 1702 bool recursively = flags & wxPG_RECURSE ? true : false;
d7e2b522
JS
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 }
1c4293cb 1716
d7e2b522
JS
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 );
1c4293cb
VZ
1732}
1733
1c4293cb
VZ
1734wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const
1735{
1736 return NULL;
1737}
1738
1739bool wxPGProperty::DoSetAttribute( const wxString& WXUNUSED(name), wxVariant& WXUNUSED(value) )
1740{
1741 return false;
1742}
1743
1744void 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
1756void 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
1765wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
1766{
1767 return wxVariant();
1768}
1769
1770
1771wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
1772{
1773 return m_attributes.FindValue(name);
1774}
1775
1776wxString 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
1786long wxPGProperty::GetAttributeAsLong( const wxString& name, long defVal ) const
1787{
1788 wxVariant variant = m_attributes.FindValue(name);
1789
4e00b908
JS
1790 if ( variant.IsNull() )
1791 return defVal;
1792
1793 return variant.GetLong();
1c4293cb
VZ
1794}
1795
1796double wxPGProperty::GetAttributeAsDouble( const wxString& name, double defVal ) const
1797{
1c4293cb
VZ
1798 wxVariant variant = m_attributes.FindValue(name);
1799
4e00b908
JS
1800 if ( variant.IsNull() )
1801 return defVal;
1c4293cb 1802
4e00b908 1803 return variant.GetDouble();
1c4293cb
VZ
1804}
1805
1806wxVariant 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
1821const unsigned int gs_propFlagToStringSize = 14;
1822
a243da29 1823static const wxChar* const gs_propFlagToString[gs_propFlagToStringSize] = {
1c4293cb
VZ
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
1840wxString 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);
6636ef8d 1853 if ( !s.empty() )
1c4293cb
VZ
1854 s << wxS("|");
1855 s << fs;
1856 }
1857 a = a << 1;
1858 }
1859
1860 return s;
1861}
1862
1863void 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
1883wxValidator* wxPGProperty::DoGetValidator() const
1884{
d3b9f782 1885 return NULL;
1c4293cb
VZ
1886}
1887
939d9364 1888int wxPGProperty::InsertChoice( const wxString& label, int index, int value )
1c4293cb 1889{
939d9364
JS
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;
1c4293cb
VZ
1910}
1911
939d9364
JS
1912
1913void wxPGProperty::DeleteChoice( int index )
1c4293cb 1914{
939d9364
JS
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);
1c4293cb
VZ
1938}
1939
939d9364 1940int wxPGProperty::GetChoiceSelection() const
1c4293cb 1941{
939d9364
JS
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;
1c4293cb
VZ
1963}
1964
939d9364 1965void wxPGProperty::SetChoiceSelection( int newValue )
1c4293cb 1966{
939d9364
JS
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") );
1c4293cb 1972
939d9364
JS
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 }
1c4293cb
VZ
1981}
1982
75ac0891 1983bool wxPGProperty::SetChoices( const wxPGChoices& choices )
1c4293cb 1984{
26b22ae3
JS
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
939d9364 1991 m_choices.Assign(choices);
1c4293cb 1992
1c4293cb 1993 {
939d9364
JS
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;
1c4293cb 1999
939d9364 2000 SetValue(defVal);
1c4293cb 2001 }
939d9364
JS
2002
2003 return true;
1c4293cb
VZ
2004}
2005
2006
2007const 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
80a46597 2023 if ( wxDynamicCast(editor, wxPGTextCtrlAndButtonEditor) )
c26873c8 2024 editor = wxPGEditor_ChoiceAndButton;
1c4293cb
VZ
2025
2026 // TextCtrl -> ComboBox
80a46597 2027 else if ( wxDynamicCast(editor, wxPGTextCtrlEditor) )
c26873c8 2028 editor = wxPGEditor_ComboBox;
1c4293cb
VZ
2029 }
2030
2031 return editor;
2032}
2033
3ded4b22
JS
2034bool 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
2043bool 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
1c4293cb
VZ
2060bool 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
1c4293cb
VZ
2075bool 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
2090void wxPGProperty::SetValueImage( wxBitmap& bmp )
2091{
2092 delete m_valueBitmap;
2093
a1b806b9 2094 if ( &bmp && bmp.IsOk() )
1c4293cb
VZ
2095 {
2096 // Resize the image
2097 wxSize maxSz = GetGrid()->GetImageSize();
2098 wxSize imSz(bmp.GetWidth(),bmp.GetHeight());
2099
4aee8334 2100 if ( imSz.y != maxSz.y )
1c4293cb 2101 {
0429e043 2102 #if wxUSE_IMAGE
28e27c34
JS
2103 // Here we use high-quality wxImage scaling functions available
2104 wxImage img = bmp.ConvertToImage();
1c4293cb 2105 double scaleY = (double)maxSz.y / (double)imSz.y;
026f3f9b
VZ
2106 img.Rescale(wxRound(bmp.GetWidth()*scaleY),
2107 wxRound(bmp.GetHeight()*scaleY),
28e27c34
JS
2108 wxIMAGE_QUALITY_HIGH);
2109 wxBitmap* bmpNew = new wxBitmap(img, 32);
0429e043
JS
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
1c4293cb
VZ
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
2137wxPGProperty* 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
2152const 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
2163bool 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
2179wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const
2180{
2181 wxPropertyGridPageState* state = GetParentState();
e777bd14
JS
2182 if ( !state )
2183 return NULL;
1c4293cb
VZ
2184 wxPropertyGrid* propGrid = state->GetGrid();
2185 if ( state == propGrid->GetState() )
2186 return propGrid;
2187 return NULL;
2188}
2189
2190
2191int 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() )
9869c262 2201 return parent->GetY2(lh);
1c4293cb
VZ
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
2213int wxPGProperty::GetY() const
2214{
2215 return GetY2(GetGrid()->GetRowHeight());
2216}
2217
1c4293cb 2218// This is used by Insert etc.
48a32cf6
JS
2219void wxPGProperty::DoAddChild( wxPGProperty* prop, int index,
2220 bool correct_mode )
1c4293cb 2221{
f7a094e1 2222 if ( index < 0 || (size_t)index >= m_children.size() )
1c4293cb 2223 {
f7a094e1
JS
2224 if ( correct_mode ) prop->m_arrIndex = m_children.size();
2225 m_children.push_back( prop );
1c4293cb
VZ
2226 }
2227 else
2228 {
f7a094e1 2229 m_children.insert( m_children.begin()+index, prop);
1b895132 2230 if ( correct_mode ) FixIndicesOfChildren( index );
1c4293cb
VZ
2231 }
2232
2233 prop->m_parent = this;
2234}
2235
48a32cf6 2236void wxPGProperty::DoPreAddChild( int index, wxPGProperty* prop )
1c4293cb 2237{
d665918b 2238 wxASSERT_MSG( prop->GetBaseName().length(),
48a32cf6
JS
2239 "Property's children must have unique, non-empty "
2240 "names within their scope" );
d665918b 2241
48a32cf6
JS
2242 prop->m_arrIndex = index;
2243 m_children.insert( m_children.begin()+index,
2244 prop );
1c4293cb
VZ
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
48a32cf6
JS
2253void 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
2267void wxPGProperty::AddChild( wxPGProperty* prop )
2268{
2269 AddPrivateChild(prop);
2270}
2271#endif
2272
2273wxPGProperty* 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
d8c74d04
JS
2299void 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 {
3ba703f9 2308 children.erase(it);
d8c74d04
JS
2309 break;
2310 }
2311 }
2312}
1c4293cb
VZ
2313
2314void 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
1c4293cb
VZ
2335 unsigned int i;
2336 unsigned int n = 0;
df04f800 2337 wxVariant childValue = list[n];
1c4293cb 2338
d665918b 2339 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
1c4293cb
VZ
2340
2341 for ( i=0; i<GetChildCount(); i++ )
2342 {
2343 const wxPGProperty* child = Item(i);
2344
d665918b 2345 if ( childValue.GetName() == child->GetBaseName() )
1c4293cb
VZ
2346 {
2347 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2348
0372d42e 2349 if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2350 {
2351 wxVariant cv2(child->GetValue());
2352 child->AdaptListToValue(childValue, &cv2);
2353 childValue = cv2;
2354 }
2355
2356 if ( allChildrenSpecified )
b8b1ff48
JS
2357 {
2358 *value = ChildChanged(*value, i, childValue);
2359 }
2360
1c4293cb
VZ
2361 n++;
2362 if ( n == (unsigned int)list.GetCount() )
2363 break;
2364 childValue = list[n];
2365 }
2366 }
2367}
2368
2369
1b895132 2370void wxPGProperty::FixIndicesOfChildren( unsigned int starthere )
1c4293cb
VZ
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)
2379wxPGProperty* 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 )
d3b9f782 2393 return NULL;
1c4293cb
VZ
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
d665918b 2403wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const
1c4293cb
VZ
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);
d665918b 2418 if ( p->m_name == name )
1c4293cb
VZ
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
2432int 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
14bac4b5
JS
2471wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y,
2472 unsigned int lh,
2473 unsigned int* nextItemY ) const
1c4293cb
VZ
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 )
43b2d5e7 2523 {
1c4293cb 2524 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
43b2d5e7 2525 }
1c4293cb 2526 else
43b2d5e7 2527 {
1c4293cb 2528 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
43b2d5e7 2529 }
1c4293cb
VZ
2530 */
2531
2532 return (wxPGProperty*) result;
2533}
2534
2535void wxPGProperty::Empty()
2536{
2537 size_t i;
2538 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES) )
2539 {
2540 for ( i=0; i<GetChildCount(); i++ )
2541 {
f7a094e1 2542 delete m_children[i];
1c4293cb
VZ
2543 }
2544 }
2545
f7a094e1 2546 m_children.clear();
1c4293cb
VZ
2547}
2548
14bac4b5
JS
2549wxPGProperty* wxPGProperty::GetItemAtY( unsigned int y ) const
2550{
2551 unsigned int nextItem;
2552 return GetItemAtY( y, GetGrid()->GetRowHeight(), &nextItem);
2553}
2554
91c818f8
JS
2555void wxPGProperty::DeleteChildren()
2556{
2557 wxPropertyGridPageState* state = m_parentState;
2558
e4e55c06
JS
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 )
91c818f8 2566 {
e4e55c06
JS
2567 i--;
2568 state->DoDelete(Item(i), true);
91c818f8
JS
2569 }
2570}
2571
1d8340b9 2572bool wxPGProperty::IsChildSelected( bool recursive ) const
a6ca624a
JS
2573{
2574 size_t i;
2575 for ( i = 0; i < GetChildCount(); i++ )
2576 {
1d8340b9
JS
2577 wxPGProperty* child = Item(i);
2578
2579 // Test child
2580 if ( m_parentState->DoIsPropertySelected( child ) )
2581 return true;
2582
2583 // Test sub-childs
2584 if ( recursive && child->IsChildSelected( recursive ) )
a6ca624a
JS
2585 return true;
2586 }
2587
2588 return false;
2589}
2590
b8b1ff48
JS
2591wxVariant wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue),
2592 int WXUNUSED(childIndex),
2593 wxVariant& WXUNUSED(childValue) ) const
1c4293cb 2594{
b8b1ff48 2595 return wxNullVariant;
1c4293cb
VZ
2596}
2597
2598bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const
2599{
2600 unsigned int i;
2601
2602 const wxVariantList* pList = NULL;
2603 wxVariantList::const_iterator node;
2604
2605 if ( pendingList )
2606 {
2607 pList = &pendingList->GetList();
2608 node = pList->begin();
2609 }
2610
1c4293cb
VZ
2611 for ( i=0; i<GetChildCount(); i++ )
2612 {
2613 wxPGProperty* child = Item(i);
2614 const wxVariant* listValue = NULL;
2615 wxVariant value;
2616
2617 if ( pendingList )
2618 {
d665918b 2619 const wxString& childName = child->GetBaseName();
1c4293cb 2620
b7bc9d80 2621 for ( ; node != pList->end(); ++node )
1c4293cb
VZ
2622 {
2623 const wxVariant& item = *((const wxVariant*)*node);
d665918b 2624 if ( item.GetName() == childName )
1c4293cb
VZ
2625 {
2626 listValue = &item;
2627 value = item;
2628 break;
2629 }
2630 }
2631 }
2632
2633 if ( !listValue )
2634 value = child->GetValue();
2635
2636 if ( value.IsNull() )
2637 return false;
2638
2639 // Check recursively
2640 if ( child->GetChildCount() )
2641 {
2642 const wxVariant* childList = NULL;
2643
0372d42e 2644 if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST )
1c4293cb
VZ
2645 childList = listValue;
2646
2647 if ( !child->AreAllChildrenSpecified((wxVariant*)childList) )
2648 return false;
2649 }
2650 }
2651
2652 return true;
2653}
2654
2655wxPGProperty* wxPGProperty::UpdateParentValues()
2656{
2657 wxPGProperty* parent = m_parent;
2658 if ( parent && parent->HasFlag(wxPG_PROP_COMPOSED_VALUE) &&
2659 !parent->IsCategory() && !parent->IsRoot() )
2660 {
2661 wxString s;
c82a80e8 2662 parent->DoGenerateComposedValue(s);
1c4293cb
VZ
2663 parent->m_value = s;
2664 return parent->UpdateParentValues();
2665 }
2666 return this;
2667}
2668
2669bool wxPGProperty::IsTextEditable() const
2670{
2671 if ( HasFlag(wxPG_PROP_READONLY) )
2672 return false;
2673
2674 if ( HasFlag(wxPG_PROP_NOEDITOR) &&
2675 (GetChildCount() ||
2676 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2677 )
2678 return false;
2679
2680 return true;
2681}
2682
1c4293cb
VZ
2683// Call after fixed sub-properties added/removed after creation.
2684// if oldSelInd >= 0 and < new max items, then selection is
2685// moved to it. Note: oldSelInd -2 indicates that this property
2686// should be selected.
2687void wxPGProperty::SubPropsChanged( int oldSelInd )
2688{
2689 wxPropertyGridPageState* state = GetParentState();
2690 wxPropertyGrid* grid = state->GetGrid();
2691
2fd4a524
JS
2692 //
2693 // Re-repare children (recursively)
2694 for ( unsigned int i=0; i<GetChildCount(); i++ )
2695 {
2696 wxPGProperty* child = Item(i);
2697 child->InitAfterAdded(state, grid);
2698 }
1c4293cb 2699
d3b9f782 2700 wxPGProperty* sel = NULL;
f7a094e1
JS
2701 if ( oldSelInd >= (int)m_children.size() )
2702 oldSelInd = (int)m_children.size() - 1;
1c4293cb
VZ
2703
2704 if ( oldSelInd >= 0 )
f7a094e1 2705 sel = m_children[oldSelInd];
1c4293cb
VZ
2706 else if ( oldSelInd == -2 )
2707 sel = this;
2708
2709 if ( sel )
2710 state->DoSelectProperty(sel);
2711
2712 if ( state == grid->GetState() )
2713 {
2714 grid->GetPanel()->Refresh();
2715 }
2716}
2717
2718// -----------------------------------------------------------------------
2719// wxPGRootProperty
2720// -----------------------------------------------------------------------
2721
2722WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl)
2723IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty)
2724
2725
94b8ecf1 2726wxPGRootProperty::wxPGRootProperty( const wxString& name )
1c4293cb
VZ
2727 : wxPGProperty()
2728{
94b8ecf1
JS
2729 m_name = name;
2730 m_label = m_name;
1c4293cb
VZ
2731 SetParentalType(0);
2732 m_depth = 0;
2733}
2734
2735
2736wxPGRootProperty::~wxPGRootProperty()
2737{
2738}
2739
2740
2741// -----------------------------------------------------------------------
2742// wxPropertyCategory
2743// -----------------------------------------------------------------------
2744
2745WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory,none,TextCtrl)
2746IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory, wxPGProperty)
2747
2748void wxPropertyCategory::Init()
2749{
2750 // don't set colour - prepareadditem method should do this
2751 SetParentalType(wxPG_PROP_CATEGORY);
2752 m_capFgColIndex = 1;
2753 m_textExtent = -1;
2754}
2755
2756wxPropertyCategory::wxPropertyCategory()
2757 : wxPGProperty()
2758{
2759 Init();
2760}
2761
2762
2763wxPropertyCategory::wxPropertyCategory( const wxString &label, const wxString& name )
2764 : wxPGProperty(label,name)
2765{
2766 Init();
2767}
2768
2769
2770wxPropertyCategory::~wxPropertyCategory()
2771{
2772}
2773
2774
1425eca5
JS
2775wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value),
2776 int WXUNUSED(argFlags) ) const
1c4293cb 2777{
e16bff8e
JS
2778 if ( m_value.GetType() == wxPG_VARIANT_TYPE_STRING )
2779 return m_value.GetString();
1c4293cb
VZ
2780 return wxEmptyString;
2781}
2782
e16bff8e
JS
2783wxString wxPropertyCategory::GetValueAsString( int argFlags ) const
2784{
2785#if wxPG_COMPATIBILITY_1_4
2786 // This is backwards compatibility test
2787 // That is, to make sure this function is not overridden
2788 // (instead, ValueToString() should be).
2789 if ( argFlags == 0xFFFF )
2790 {
2791 // Do not override! (for backwards compliancy)
2792 return g_invalidStringContent;
2793 }
2794#endif
2795
2796 // Unspecified value is always empty string
2797 if ( IsValueUnspecified() )
2798 return wxEmptyString;
2799
2800 return wxPGProperty::GetValueAsString(argFlags);
2801}
2802
1c4293cb
VZ
2803int wxPropertyCategory::GetTextExtent( const wxWindow* wnd, const wxFont& font ) const
2804{
2805 if ( m_textExtent > 0 )
2806 return m_textExtent;
2807 int x = 0, y = 0;
03647350 2808 ((wxWindow*)wnd)->GetTextExtent( m_label, &x, &y, 0, 0, &font );
1c4293cb
VZ
2809 return x;
2810}
2811
2812void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font )
2813{
2814 int x = 0, y = 0;
03647350 2815 wnd->GetTextExtent( m_label, &x, &y, 0, 0, &font );
1c4293cb
VZ
2816 m_textExtent = x;
2817}
2818
2728c3bf
JS
2819// -----------------------------------------------------------------------
2820// wxPGChoices
2821// -----------------------------------------------------------------------
2822
2823wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, int value )
2824{
2825 AllocExclusive();
2826
2827 wxPGChoiceEntry entry(label, value);
2828 return m_data->Insert( -1, entry );
2829}
2830
2831// -----------------------------------------------------------------------
2832
2833wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, const wxBitmap& bitmap, int value )
2834{
2835 AllocExclusive();
2836
2837 wxPGChoiceEntry entry(label, value);
2838 entry.SetBitmap(bitmap);
2839 return m_data->Insert( -1, entry );
2840}
2841
2842// -----------------------------------------------------------------------
2843
2844wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index )
2845{
2846 AllocExclusive();
2847
2848 return m_data->Insert( index, entry );
2849}
2850
2851// -----------------------------------------------------------------------
2852
2853wxPGChoiceEntry& wxPGChoices::Insert( const wxString& label, int index, int value )
2854{
2855 AllocExclusive();
2856
2857 wxPGChoiceEntry entry(label, value);
2858 return m_data->Insert( index, entry );
2859}
2860
2861// -----------------------------------------------------------------------
2862
2863wxPGChoiceEntry& wxPGChoices::AddAsSorted( const wxString& label, int value )
2864{
2865 AllocExclusive();
2866
2867 size_t index = 0;
2868
2869 while ( index < GetCount() )
2870 {
2871 int cmpRes = GetLabel(index).Cmp(label);
2872 if ( cmpRes > 0 )
2873 break;
2874 index++;
2875 }
2876
2877 wxPGChoiceEntry entry(label, value);
2878 return m_data->Insert( index, entry );
2879}
2880
2881// -----------------------------------------------------------------------
2882
a243da29 2883void wxPGChoices::Add( const wxChar* const* labels, const ValArrItem* values )
2728c3bf
JS
2884{
2885 AllocExclusive();
2886
2887 unsigned int itemcount = 0;
a243da29 2888 const wxChar* const* p = &labels[0];
2728c3bf
JS
2889 while ( *p ) { p++; itemcount++; }
2890
2891 unsigned int i;
2892 for ( i = 0; i < itemcount; i++ )
2893 {
2894 int value = i;
2895 if ( values )
2896 value = values[i];
2897 wxPGChoiceEntry entry(labels[i], value);
2898 m_data->Insert( i, entry );
2899 }
2900}
2901
2902// -----------------------------------------------------------------------
2903
2904void wxPGChoices::Add( const wxArrayString& arr, const wxArrayInt& arrint )
2905{
2906 AllocExclusive();
2907
2908 unsigned int i;
2909 unsigned int itemcount = arr.size();
2910
2911 for ( i = 0; i < itemcount; i++ )
2912 {
2913 int value = i;
2914 if ( &arrint && arrint.size() )
2915 value = arrint[i];
2916 wxPGChoiceEntry entry(arr[i], value);
2917 m_data->Insert( i, entry );
2918 }
2919}
2920
2921// -----------------------------------------------------------------------
2922
2923void wxPGChoices::RemoveAt(size_t nIndex, size_t count)
2924{
2925 AllocExclusive();
2926
92ffc98a 2927 wxASSERT( m_data->GetRefCount() != -1 );
2728c3bf
JS
2928 m_data->m_items.erase(m_data->m_items.begin()+nIndex,
2929 m_data->m_items.begin()+nIndex+count);
2930}
2931
2932// -----------------------------------------------------------------------
2933
2934void wxPGChoices::Clear()
2935{
2936 if ( m_data != wxPGChoicesEmptyData )
2937 {
2938 AllocExclusive();
2939 m_data->Clear();
2940 }
2941}
2942
2943// -----------------------------------------------------------------------
2944
2945int wxPGChoices::Index( const wxString& str ) const
2946{
2947 if ( IsOk() )
2948 {
2949 unsigned int i;
2950 for ( i=0; i< m_data->GetCount(); i++ )
2951 {
2952 const wxPGChoiceEntry& entry = m_data->Item(i);
2953 if ( entry.HasText() && entry.GetText() == str )
2954 return i;
2955 }
2956 }
2957 return -1;
2958}
2959
2960// -----------------------------------------------------------------------
2961
2962int wxPGChoices::Index( int val ) const
2963{
2964 if ( IsOk() )
2965 {
2966 unsigned int i;
2967 for ( i=0; i< m_data->GetCount(); i++ )
2968 {
2969 const wxPGChoiceEntry& entry = m_data->Item(i);
2970 if ( entry.GetValue() == val )
2971 return i;
2972 }
2973 }
2974 return -1;
2975}
2976
2977// -----------------------------------------------------------------------
2978
2979wxArrayString wxPGChoices::GetLabels() const
2980{
2981 wxArrayString arr;
2982 unsigned int i;
2983
2984 if ( this && IsOk() )
2985 for ( i=0; i<GetCount(); i++ )
2986 arr.push_back(GetLabel(i));
2987
2988 return arr;
2989}
2990
2991// -----------------------------------------------------------------------
2992
2993wxArrayInt wxPGChoices::GetValuesForStrings( const wxArrayString& strings ) const
2994{
2995 wxArrayInt arr;
2996
2997 if ( IsOk() )
2998 {
2999 unsigned int i;
3000 for ( i=0; i< strings.size(); i++ )
3001 {
3002 int index = Index(strings[i]);
3003 if ( index >= 0 )
3004 arr.Add(GetValue(index));
3005 else
3006 arr.Add(wxPG_INVALID_VALUE);
3007 }
3008 }
3009
3010 return arr;
3011}
3012
3013// -----------------------------------------------------------------------
3014
3015wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings,
3016 wxArrayString* unmatched ) const
3017{
3018 wxArrayInt arr;
3019
3020 if ( IsOk() )
3021 {
3022 unsigned int i;
3023 for ( i=0; i< strings.size(); i++ )
3024 {
3025 const wxString& str = strings[i];
3026 int index = Index(str);
3027 if ( index >= 0 )
3028 arr.Add(index);
3029 else if ( unmatched )
3030 unmatched->Add(str);
3031 }
3032 }
3033
3034 return arr;
3035}
3036
3037// -----------------------------------------------------------------------
3038
3039void wxPGChoices::AllocExclusive()
3040{
3041 EnsureData();
3042
92ffc98a 3043 if ( m_data->GetRefCount() != 1 )
2728c3bf
JS
3044 {
3045 wxPGChoicesData* data = new wxPGChoicesData();
3046 data->CopyDataFrom(m_data);
3047 Free();
3048 m_data = data;
3049 }
3050}
3051
3052// -----------------------------------------------------------------------
3053
3054void wxPGChoices::AssignData( wxPGChoicesData* data )
3055{
3056 Free();
3057
3058 if ( data != wxPGChoicesEmptyData )
3059 {
3060 m_data = data;
92ffc98a 3061 data->IncRef();
2728c3bf
JS
3062 }
3063}
3064
3065// -----------------------------------------------------------------------
3066
3067void wxPGChoices::Init()
3068{
3069 m_data = wxPGChoicesEmptyData;
3070}
3071
3072// -----------------------------------------------------------------------
3073
3074void wxPGChoices::Free()
3075{
3076 if ( m_data != wxPGChoicesEmptyData )
3077 {
3078 m_data->DecRef();
3079 m_data = wxPGChoicesEmptyData;
3080 }
3081}
3082
1c4293cb
VZ
3083// -----------------------------------------------------------------------
3084// wxPGAttributeStorage
3085// -----------------------------------------------------------------------
3086
3087wxPGAttributeStorage::wxPGAttributeStorage()
3088{
3089}
3090
3091wxPGAttributeStorage::~wxPGAttributeStorage()
3092{
3093 wxPGHashMapS2P::iterator it;
3094
b7bc9d80 3095 for ( it = m_map.begin(); it != m_map.end(); ++it )
1c4293cb
VZ
3096 {
3097 wxVariantData* data = (wxVariantData*) it->second;
3098 data->DecRef();
3099 }
3100}
3101
3102void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value )
3103{
3104 wxVariantData* data = value.GetData();
3105
3106 // Free old, if any
3107 wxPGHashMapS2P::iterator it = m_map.find(name);
3108 if ( it != m_map.end() )
1802a91d 3109 {
1c4293cb
VZ
3110 ((wxVariantData*)it->second)->DecRef();
3111
1802a91d
JS
3112 if ( !data )
3113 {
3114 // If Null variant, just remove from set
3115 m_map.erase(it);
3116 return;
3117 }
3118 }
3119
1c4293cb 3120 if ( data )
1802a91d 3121 {
1c4293cb
VZ
3122 data->IncRef();
3123
1802a91d
JS
3124 m_map[name] = data;
3125 }
1c4293cb
VZ
3126}
3127
f4bc1aa2 3128#endif // wxUSE_PROPGRID