1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        props.cpp
3 // Purpose:     Basic Property Classes
4 // Author:      Jaakko Salli
5 // Modified by:
6 // Created:     May-14-2004
7 // RCS-ID:      $Id:
8 // Copyright:   (c) Jaakko Salli
9 // Licence:     wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14 
15 #ifdef __BORLANDC__
16     #pragma hdrstop
17 #endif
18 
19 #ifndef WX_PRECOMP
20     #include "wx/defs.h"
21     #include "wx/object.h"
22     #include "wx/hash.h"
23     #include "wx/string.h"
24     #include "wx/log.h"
25     #include "wx/event.h"
26     #include "wx/window.h"
27     #include "wx/panel.h"
28     #include "wx/dc.h"
29     #include "wx/dcclient.h"
30     #include "wx/dcmemory.h"
31     #include "wx/button.h"
32     #include "wx/pen.h"
33     #include "wx/brush.h"
34     #include "wx/cursor.h"
35     #include "wx/dialog.h"
36     #include "wx/settings.h"
37     #include "wx/msgdlg.h"
38     #include "wx/choice.h"
39     #include "wx/stattext.h"
40     #include "wx/scrolwin.h"
41     #include "wx/dirdlg.h"
42     #include "wx/combobox.h"
43     #include "wx/layout.h"
44     #include "wx/sizer.h"
45     #include "wx/textdlg.h"
46     #include "wx/filedlg.h"
47     #include "wx/statusbr.h"
48     #include "wx/intl.h"
49 #endif
50 
51 #include <wx/filename.h>
52 
53 #include <wx/propgrid/propgrid.h>
54 
55 #include <wx/propgrid/propdev.h>
56 
57 
58 #define wxPG_CUSTOM_IMAGE_WIDTH     20 // for wxColourProperty etc.
59 
60 
61 // -----------------------------------------------------------------------
62 // wxStringProperty
63 // -----------------------------------------------------------------------
64 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty,wxPGProperty,wxString,const wxString &,TextCtrl)65 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty,wxPGProperty,
66                                wxString,const wxString&,TextCtrl)
67 
68 wxStringProperty::wxStringProperty( const wxString& label,
69                                     const wxString& name,
70                                     const wxString& value )
71     : wxPGProperty(label,name)
72 {
73     SetValue(value);
74 }
75 
OnSetValue()76 void wxStringProperty::OnSetValue()
77 {
78     if ( !m_value.IsNull() && m_value.GetString() == wxT("<composed>") )
79         SetFlag(wxPG_PROP_COMPOSED_VALUE);
80 
81     if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
82     {
83         wxString s;
84         GenerateComposedValue(s, 0);
85         m_value = s;
86     }
87 }
88 
~wxStringProperty()89 wxStringProperty::~wxStringProperty() { }
90 
GetValueAsString(int argFlags) const91 wxString wxStringProperty::GetValueAsString( int argFlags ) const
92 {
93     wxString s = m_value.GetString();
94 
95     if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE) )
96     {
97         // Value stored in m_value is non-editable, non-full value
98         if ( (argFlags & wxPG_FULL_VALUE) || (argFlags & wxPG_EDITABLE_VALUE) )
99             GenerateComposedValue(s, argFlags);
100 
101         return s;
102     }
103 
104     // If string is password and value is for visual purposes,
105     // then return asterisks instead the actual string.
106     if ( (m_flags & wxPG_PROP_PASSWORD) && !(argFlags & (wxPG_FULL_VALUE|wxPG_EDITABLE_VALUE)) )
107         return wxString(wxChar('*'), s.Length());
108 
109     return s;
110 }
111 
StringToValue(wxVariant & variant,const wxString & text,int argFlags) const112 bool wxStringProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
113 {
114     if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE) )
115         return wxPGProperty::StringToValue(variant, text, argFlags);
116 
117     if ( m_value.IsNull() || m_value.GetString() != text )
118     {
119         variant = text;
120         return true;
121     }
122 
123     return false;
124 }
125 
DoSetAttribute(const wxString & name,wxVariant & value)126 bool wxStringProperty::DoSetAttribute( const wxString& name, wxVariant& value )
127 {
128     if ( name == wxPG_STRING_PASSWORD )
129     {
130         m_flags &= ~(wxPG_PROP_PASSWORD);
131         if ( wxPGVariantToInt(value) ) m_flags |= wxPG_PROP_PASSWORD;
132         RecreateEditor();
133         return false;
134     }
135     return true;
136 }
137 
138 // -----------------------------------------------------------------------
139 
140 #ifndef wxHAS_STRTOLL
141     #if wxCHECK_VERSION(3, 0, 0)
142         #define wxHAS_STRTOLL
143     #endif
144 #endif
145 
146 #ifndef wxINT64_MAX
147     #ifdef LLONG_MAX
148         #define wxINT64_MAX LLONG_MAX
149         #define wxINT64_MIN LLONG_MIN
150     #else
151         #define wxINT64_MAX wxLL(9223372036854775807)
152         #define wxINT64_MIN (wxLL(-9223372036854775807)-1)
153     #endif
154 #endif
155 
156 #ifndef wxUINT64_MAX
157     #define wxUINT64_MAX wxULL(0xFFFFFFFFFFFFFFFF)
158     #define wxUINT64_MIN wxULL(0)
159 #endif
160 
161 #ifndef wxHAS_STRTOLL
162 
163 #ifndef wxSET_ERRNO
164     #define wxSET_ERRNO(A)  errno = A
165 #endif
166 
167 #include <errno.h>
168 
wxStrtoullBase(const wxChar * nptr,wxChar ** endptr,int base,wxChar * sign)169 static wxULongLong_t wxStrtoullBase(const wxChar* nptr, wxChar** endptr, int base, wxChar* sign)
170 {
171     wxULongLong_t sum = 0;
172     wxString wxstr(nptr);
173     wxString::const_iterator i = wxstr.begin();
174     wxString::const_iterator end = wxstr.end();
175 
176     // Skip spaces
177     while ( i != end && wxIsspace(*i) ) i++;
178 
179     // Starts with sign?
180     *sign = wxT(' ');
181     if ( i != end )
182     {
183         wxChar c = *i;
184         if ( c == wxT('+') || c == wxT('-') )
185         {
186             *sign = c;
187             i++;
188         }
189     }
190 
191     // Starts with 0x?
192     if ( i != end && *i == wxT('0') )
193     {
194         i++;
195         if ( i != end )
196         {
197             if ( *i == wxT('x') && (base == 16 || base == 0) )
198             {
199                 base = 16;
200                 i++;
201             }
202             else
203             {
204                 if ( endptr )
205                     *endptr = (wxChar*) nptr;
206                 wxSET_ERRNO(EINVAL);
207                 return sum;
208             }
209         }
210         else
211             i--;
212     }
213 
214     if ( base == 0 )
215         base = 10;
216 
217     for ( ; i != end; i++ )
218     {
219         unsigned int n;
220 
221         wxChar c = *i;
222         if ( c >= wxT('0') )
223         {
224             if ( c <= wxT('9') )
225                 n = c - wxT('0');
226             else
227                 n = wxTolower(c) - wxT('a') + 10;
228         }
229         else
230             break;
231 
232         if ( n >= (unsigned int)base )
233             // Invalid character (for this base)
234             break;
235 
236         wxULongLong_t prevsum = sum;
237         sum = (sum * base) + n;
238 
239         if ( sum < prevsum )
240         {
241             wxSET_ERRNO(ERANGE);
242             break;
243         }
244     }
245 
246     if ( endptr )
247     {
248         *endptr = (wxChar*)(nptr + (i - wxstr.begin()));
249     }
250 
251     return sum;
252 }
253 
254 wxULongLong_t wxStrtoull(const wxChar* nptr, wxChar** endptr, int base);
wxStrtoull(const wxChar * nptr,wxChar ** endptr,int base)255 wxULongLong_t wxStrtoull(const wxChar* nptr, wxChar** endptr, int base)
256 {
257     wxChar sign;
258     wxULongLong_t uval = wxStrtoullBase(nptr, endptr, base, &sign);
259 
260     if ( sign == wxT('-') )
261     {
262         wxSET_ERRNO(ERANGE);
263         uval = 0;
264     }
265 
266     return uval;
267 }
268 
269 wxLongLong_t wxStrtoll(const wxChar* nptr, wxChar** endptr, int base);
wxStrtoll(const wxChar * nptr,wxChar ** endptr,int base)270 wxLongLong_t wxStrtoll(const wxChar* nptr, wxChar** endptr, int base)
271 {
272     wxChar sign;
273     wxULongLong_t uval = wxStrtoullBase(nptr, endptr, base, &sign);
274     wxLongLong_t val = 0;
275 
276     if ( sign == wxT('-') )
277     {
278         if ( uval <= wxULL(wxINT64_MAX+1) )
279         {
280             if ( uval == wxULL(wxINT64_MAX+1))
281                 val = -((wxLongLong_t)wxINT64_MAX) - 1;
282             else
283                 val = -((wxLongLong_t)uval);
284         }
285         else
286         {
287             wxSET_ERRNO(ERANGE);
288         }
289     }
290     else if ( uval <= wxINT64_MAX )
291     {
292         val = uval;
293     }
294     else
295     {
296         wxSET_ERRNO(ERANGE);
297     }
298 
299     return val;
300 }
301 
wxPGStringToLongLong(const wxString s,wxLongLong_t * val,int base)302 bool wxPGStringToLongLong(const wxString s, wxLongLong_t* val, int base)
303 {
304     wxChar* endptr;
305     errno = 0;
306     *val = wxStrtoll(s.c_str(), &endptr, base);
307     return (errno == 0 && *endptr == wxT('\0'));
308 }
309 
wxPGStringToULongLong(const wxString s,wxULongLong_t * val,int base)310 bool wxPGStringToULongLong(const wxString s, wxULongLong_t* val, int base)
311 {
312     wxChar* endptr;
313     errno = 0;
314     *val = wxStrtoull(s.c_str(), &endptr, base);
315     return (errno == 0 && *endptr == wxT('\0'));
316 }
317 
318 #else
319 
wxPGStringToLongLong(const wxString s,wxLongLong_t * val,int base)320 bool wxPGStringToLongLong(const wxString s, wxLongLong_t* val, int base)
321 {
322     return s.ToLongLong(val, base);
323 }
324 
wxPGStringToULongLong(const wxString s,wxULongLong_t * val,int base)325 bool wxPGStringToULongLong(const wxString s, wxULongLong_t* val, int base)
326 {
327     return s.ToULongLong(val, base);
328 }
329 
330 #endif // !wxHAS_STRTOLL
331 
332 // -----------------------------------------------------------------------
333 // wxNumericPropertyValidator
334 // -----------------------------------------------------------------------
335 
336 #if wxUSE_VALIDATORS
337 
338 wxNumericPropertyValidator::
wxNumericPropertyValidator(NumericType numericType,int base)339     wxNumericPropertyValidator( NumericType numericType, int base )
340     : wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST)
341 {
342     wxArrayString arr;
343     arr.Add(wxT("0"));
344     arr.Add(wxT("1"));
345     arr.Add(wxT("2"));
346     arr.Add(wxT("3"));
347     arr.Add(wxT("4"));
348     arr.Add(wxT("5"));
349     arr.Add(wxT("6"));
350     arr.Add(wxT("7"));
351 
352     if ( base >= 10 )
353     {
354         arr.Add(wxT("8"));
355         arr.Add(wxT("9"));
356         if ( base >= 16 )
357         {
358             arr.Add(wxT("a")); arr.Add(wxT("A"));
359             arr.Add(wxT("b")); arr.Add(wxT("B"));
360             arr.Add(wxT("c")); arr.Add(wxT("C"));
361             arr.Add(wxT("d")); arr.Add(wxT("D"));
362             arr.Add(wxT("e")); arr.Add(wxT("E"));
363             arr.Add(wxT("f")); arr.Add(wxT("F"));
364         }
365     }
366 
367     if ( numericType == Signed )
368     {
369         arr.Add(wxT("+"));
370         arr.Add(wxT("-"));
371     }
372     else if ( numericType == Float )
373     {
374         arr.Add(wxT("+"));
375         arr.Add(wxT("-"));
376         arr.Add(wxT("e"));
377 
378         // Use locale-specific decimal point
379         arr.Add(wxString::Format(wxT("%g"), 1.1)[1]);
380     }
381 
382     SetIncludes(arr);
383 }
384 
Validate(wxWindow * parent)385 bool wxNumericPropertyValidator::Validate(wxWindow* parent)
386 {
387     if ( !wxTextValidator::Validate(parent) )
388         return false;
389 
390     wxWindow* wnd = GetWindow();
391     if ( !wnd->IsKindOf(CLASSINFO(wxTextCtrl)) )
392         return true;
393 
394     // Do not allow zero-length string
395     wxTextCtrl* tc = static_cast<wxTextCtrl*>(wnd);
396     wxString text = tc->GetValue();
397 
398     if ( !text.length() )
399         return false;
400 
401     return true;
402 }
403 
404 #endif // wxUSE_VALIDATORS
405 
406 // -----------------------------------------------------------------------
407 // wxIntProperty
408 // -----------------------------------------------------------------------
409 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty,wxPGProperty,long,long,TextCtrl)410 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty,wxPGProperty,
411                                long,long,TextCtrl)
412 
413 wxIntProperty::wxIntProperty( const wxString& label, const wxString& name,
414     long value ) : wxPGProperty(label,name)
415 {
416     SetValue(value);
417 }
418 
wxIntProperty(const wxString & label,const wxString & name,const wxLongLong & value)419 wxIntProperty::wxIntProperty( const wxString& label, const wxString& name,
420     const wxLongLong& value ) : wxPGProperty(label,name)
421 {
422     SetValue(wxLongLongToVariant(value));
423 }
424 
~wxIntProperty()425 wxIntProperty::~wxIntProperty() { }
426 
GetValueAsString(int) const427 wxString wxIntProperty::GetValueAsString( int ) const
428 {
429     if ( wxPGIsVariantType(m_value, long) )
430         return wxString::Format(wxT("%li"),m_value.GetLong());
431 
432     wxLongLong* ll = &wxLongLongFromVariant(m_value);
433     if ( ll )
434         return ll->ToString();
435 
436     return wxEmptyString;
437 }
438 
StringToValue(wxVariant & variant,const wxString & text,int argFlags) const439 bool wxIntProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
440 {
441     wxString s;
442     long value32;
443 
444     if ( text.length() == 0 )
445     {
446         variant.MakeNull();
447         return true;
448     }
449 
450     // We know it is a number, but let's still check
451     // the return value.
452     if ( text.IsNumber() )
453     {
454         // Remove leading zeroes, so that the number is not interpreted as octal
455         wxString::const_iterator i = text.begin();
456         wxString::const_iterator iMax = text.end() - 1;  // Let's allow one, last zero though
457 
458         int firstNonZeroPos = 0;
459 
460         for ( ; i != iMax; i++ )
461         {
462             wxChar c = *i;
463             if ( c != wxT('0') && c != wxT(' ') )
464                 break;
465             firstNonZeroPos++;
466         }
467 
468         wxString useText = text.substr(firstNonZeroPos, text.length() - firstNonZeroPos);
469 
470         bool isPrevLong = wxPGIsVariantType(variant, long);
471 
472         wxLongLong_t value64 = 0;
473 
474         if ( wxPGStringToLongLong(useText, &value64, 10) &&
475              ( value64 >= INT_MAX || value64 <= INT_MIN )
476            )
477         {
478             wxLongLong* _m_value64 = &wxLongLongFromVariant(m_value);
479             if ( isPrevLong || !_m_value64 || _m_value64->GetValue() != value64 )
480             {
481                 variant = wxLongLongToVariant(value64);
482                 return true;
483             }
484         }
485 
486         if ( useText.ToLong( &value32, 0 ) )
487         {
488             if ( !isPrevLong || m_value.IsNull() || m_value.GetLong() != value32 )
489             {
490                 variant = value32;
491                 return true;
492             }
493         }
494     }
495     else if ( argFlags & wxPG_REPORT_ERROR )
496     {
497     }
498     return false;
499 }
500 
IntToValue(wxVariant & variant,int value,int WXUNUSED (argFlags)) const501 bool wxIntProperty::IntToValue( wxVariant& variant, int value, int WXUNUSED(argFlags) ) const
502 {
503     if ( !wxPGIsVariantType(variant, long) || variant.GetLong() != value )
504     {
505         variant = (long)value;
506         return true;
507     }
508     return false;
509 }
510 
DoValidation(const wxPGProperty * property,wxLongLong_t & value,wxPGValidationInfo * pValidationInfo,int mode)511 bool wxIntProperty::DoValidation( const wxPGProperty* property, wxLongLong_t& value, wxPGValidationInfo* pValidationInfo, int mode )
512 {
513     // Check for min/max
514     wxLongLong_t min = wxINT64_MIN;
515     wxLongLong_t max = wxINT64_MAX;
516     wxVariant variant;
517     bool minOk = false;
518     bool maxOk = false;
519 
520     variant = property->GetAttribute(wxPGGlobalVars->m_strMin);
521     if ( !variant.IsNull() )
522     {
523         wxPGVariantToLongLong(variant, &min);
524         minOk = true;
525     }
526 
527     variant = property->GetAttribute(wxPGGlobalVars->m_strMax);
528     if ( !variant.IsNull() )
529     {
530         wxPGVariantToLongLong(variant, &max);
531         maxOk = true;
532     }
533 
534     if ( minOk )
535     {
536         if ( value < min )
537         {
538             if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
539             {
540                 wxString msg;
541                 if ( !maxOk )
542                     msg = wxString::Format(
543                                 _("Value must be %lld or higher"), min);
544                 else
545                     msg = wxString::Format(
546                                 _("Value must be between %lld and %lld."),
547                                 min, max);
548                 pValidationInfo->m_failureMessage = msg;
549             }
550             else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
551                 value = min;
552             else
553                 value = max - (min - value);
554             return false;
555         }
556     }
557 
558     if ( maxOk )
559     {
560         if ( value > max )
561         {
562             if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
563             {
564                 wxString msg;
565                 if ( !minOk )
566                     msg = wxString::Format(
567                                 _("Value must be %lld or lower."), max);
568                 else
569                     msg = wxString::Format(
570                                 _("Value must be between %lld and %lld."),
571                                 min, max);
572                 pValidationInfo->m_failureMessage = msg;
573             }
574             else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
575                 value = max;
576             else
577                 value = min + (value - max);
578             return false;
579         }
580     }
581 
582     return true;
583 }
584 
ValidateValue(wxVariant & value,wxPGValidationInfo & validationInfo) const585 bool wxIntProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const
586 {
587     wxLongLong_t ll;
588     if ( wxPGVariantToLongLong(value, &ll) )
589         return DoValidation(this, ll, &validationInfo, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
590     return true;
591 }
592 
GetClassValidator()593 wxValidator* wxIntProperty::GetClassValidator()
594 {
595 #if wxUSE_VALIDATORS
596     WX_PG_DOGETVALIDATOR_ENTRY()
597 
598     wxValidator* validator = new wxNumericPropertyValidator(
599                                     wxNumericPropertyValidator::Signed);
600 
601     WX_PG_DOGETVALIDATOR_EXIT(validator)
602 #else
603     return NULL;
604 #endif
605 }
606 
DoGetValidator() const607 wxValidator* wxIntProperty::DoGetValidator() const
608 {
609     return GetClassValidator();
610 }
611 
612 // -----------------------------------------------------------------------
613 // wxUIntProperty
614 // -----------------------------------------------------------------------
615 
616 
617 #define wxPG_UINT_TEMPLATE_MAX 8
618 
619 static const wxChar* gs_uintTemplates32[wxPG_UINT_TEMPLATE_MAX] = {
620     wxT("%x"),wxT("0x%x"),wxT("$%x"),
621     wxT("%X"),wxT("0x%X"),wxT("$%X"),
622     wxT("%u"),wxT("%o")
623 };
624 
625 static const wxChar* gs_uintTemplates64[wxPG_UINT_TEMPLATE_MAX] = {
626     wxT("%") wxLongLongFmtSpec wxT("x"),
627     wxT("0x%") wxLongLongFmtSpec wxT("x"),
628     wxT("$%") wxLongLongFmtSpec wxT("x"),
629     wxT("%") wxLongLongFmtSpec wxT("X"),
630     wxT("0x%") wxLongLongFmtSpec wxT("X"),
631     wxT("$%") wxLongLongFmtSpec wxT("X"),
632     wxT("%") wxLongLongFmtSpec wxT("u"),
633     wxT("%") wxLongLongFmtSpec wxT("o")
634 };
635 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty,wxPGProperty,long,unsigned long,TextCtrl)636 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty,wxPGProperty,
637                                long,unsigned long,TextCtrl)
638 
639 void wxUIntProperty::Init()
640 {
641     m_base = 6; // This is magic number for dec base (must be same as in setattribute)
642     m_realBase = 10;
643     m_prefix = wxPG_PREFIX_NONE;
644 }
645 
wxUIntProperty(const wxString & label,const wxString & name,unsigned long value)646 wxUIntProperty::wxUIntProperty( const wxString& label, const wxString& name,
647     unsigned long value ) : wxPGProperty(label,name)
648 {
649     Init();
650     SetValue((long)value);
651 }
652 
wxUIntProperty(const wxString & label,const wxString & name,const wxULongLong & value)653 wxUIntProperty::wxUIntProperty( const wxString& label, const wxString& name,
654     const wxULongLong& value ) : wxPGProperty(label,name)
655 {
656     Init();
657     SetValue(wxULongLongToVariant(value));
658 }
659 
~wxUIntProperty()660 wxUIntProperty::~wxUIntProperty() { }
661 
GetValueAsString(int) const662 wxString wxUIntProperty::GetValueAsString( int ) const
663 {
664     size_t index = m_base + m_prefix;
665     if ( index >= wxPG_UINT_TEMPLATE_MAX )
666         index = wxPG_BASE_DEC;
667 
668     if ( wxPGIsVariantType(m_value, long) )
669         return wxString::Format(gs_uintTemplates32[index],(unsigned long)m_value.GetLong());
670     else
671         return wxString::Format(gs_uintTemplates64[index],wxULongLongFromVariant(m_value).GetValue());
672 }
673 
StringToValue(wxVariant & variant,const wxString & text,int WXUNUSED (argFlags)) const674 bool wxUIntProperty::StringToValue( wxVariant& variant, const wxString& text, int WXUNUSED(argFlags) ) const
675 {
676     //long unsigned value32 = 0;
677     bool isPrevLong = wxPGIsVariantType(variant, long);
678 
679     if ( text.length() == 0 )
680     {
681         variant.MakeNull();
682         return true;
683     }
684 
685     size_t start = 0;
686     if ( text[0] == wxT('$') )
687         start++;
688 
689     wxULongLong_t value64 = 0;
690     wxString s = text.substr(start, text.length() - start);
691 
692     if ( wxPGStringToULongLong(s, &value64, (unsigned int)m_realBase) )
693     {
694         if ( value64 >= LONG_MAX )
695         {
696             wxULongLong* _m_value64 = &wxULongLongFromVariant(m_value);
697             if ( isPrevLong || !_m_value64 || _m_value64->GetValue() != value64 )
698             {
699                 variant = wxULongLongToVariant(value64);
700                 return true;
701             }
702         }
703         else
704         {
705             unsigned long value32 = wxLongLong(value64).GetLo();
706             if ( !isPrevLong || m_value.GetLong() != (long)value32 )
707             {
708                 variant = (long)value32;
709                 return true;
710             }
711         }
712 
713     }
714     return false;
715 }
716 
IntToValue(wxVariant & variant,int number,int WXUNUSED (argFlags)) const717 bool wxUIntProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const
718 {
719     if ( m_value.IsNull() || m_value != (long)number )
720     {
721         variant = (long)number;
722         return true;
723     }
724     return false;
725 }
726 
ValidateValue(wxVariant & value,wxPGValidationInfo & validationInfo) const727 bool wxUIntProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const
728 {
729     // Check for min/max
730     wxULongLong_t ll;
731     if ( wxPGVariantToULongLong(value, &ll) )
732     {
733         wxULongLong_t min = wxUINT64_MIN;
734         wxULongLong_t max = wxUINT64_MAX;
735         wxVariant variant;
736 
737         variant = GetAttribute(wxPGGlobalVars->m_strMin);
738         if ( !variant.IsNull() )
739         {
740             wxPGVariantToULongLong(variant, &min);
741             if ( ll < min )
742             {
743                 validationInfo.m_failureMessage = wxString::Format(_("Value must be %llu or higher"),min);
744                 return false;
745             }
746         }
747         variant = GetAttribute(wxPGGlobalVars->m_strMax);
748         if ( !variant.IsNull() )
749         {
750             wxPGVariantToULongLong(variant, &max);
751             if ( ll > max )
752             {
753                 validationInfo.m_failureMessage = wxString::Format(_("Value must be %llu or less"),max);
754                 return false;
755             }
756         }
757     }
758     return true;
759 }
760 
DoGetValidator() const761 wxValidator* wxUIntProperty::DoGetValidator() const
762 {
763 #if wxUSE_VALIDATORS
764     WX_PG_DOGETVALIDATOR_ENTRY()
765 
766     wxValidator* validator = new wxNumericPropertyValidator(
767                                     wxNumericPropertyValidator::Unsigned,
768                                     m_realBase);
769 
770     WX_PG_DOGETVALIDATOR_EXIT(validator)
771 #else
772     return NULL;
773 #endif
774 }
775 
DoSetAttribute(const wxString & name,wxVariant & value)776 bool wxUIntProperty::DoSetAttribute( const wxString& name, wxVariant& value )
777 {
778     if ( name == wxPG_UINT_BASE )
779     {
780         int val = value.GetLong();
781 
782         m_realBase = (wxByte) val;
783         if ( m_realBase > 16 )
784             m_realBase = 16;
785 
786         //
787         // Translate logical base to a template array index
788         m_base = 7; // oct
789         if ( val == wxPG_BASE_HEX )
790             m_base = 3;
791         else if ( val == wxPG_BASE_DEC )
792             m_base = 6;
793         else if ( val == wxPG_BASE_HEXL )
794             m_base = 0;
795         return true;
796     }
797     else if ( name == wxPG_UINT_PREFIX )
798     {
799         m_prefix = (wxByte) value.GetLong();
800         return true;
801     }
802     return false;
803 }
804 
805 // -----------------------------------------------------------------------
806 // wxFloatProperty
807 // -----------------------------------------------------------------------
808 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty,wxPGProperty,double,double,TextCtrl)809 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty,wxPGProperty,
810                                double,double,TextCtrl)
811 
812 wxFloatProperty::wxFloatProperty( const wxString& label,
813                                             const wxString& name,
814                                             double value )
815     : wxPGProperty(label,name)
816 {
817     m_precision = -1;
818     SetValue(value);
819 }
820 
~wxFloatProperty()821 wxFloatProperty::~wxFloatProperty() { }
822 
823 // This helper method provides standard way for floating point-using
824 // properties to convert values to string.
DoubleToString(wxString & target,double value,int precision,bool removeZeroes,wxString * precTemplate)825 void wxPropertyGrid::DoubleToString(wxString& target,
826                                     double value,
827                                     int precision,
828                                     bool removeZeroes,
829                                     wxString* precTemplate)
830 {
831     if ( precision >= 0 )
832     {
833         wxString text1;
834         if (!precTemplate)
835             precTemplate = &text1;
836 
837         if ( !precTemplate->length() )
838         {
839             *precTemplate = wxT("%.");
840             *precTemplate << wxString::Format( wxT("%i"), precision );
841             *precTemplate << wxT('f');
842         }
843 
844         target.Printf( precTemplate->c_str(), value );
845     }
846     else
847     {
848         target.Printf( wxT("%f"), value );
849     }
850 
851     if ( removeZeroes && precision != 0 && target.length() )
852     {
853         // Remove excess zeroes (do not remove this code just yet,
854         // since sprintf can't do the same consistently across platforms).
855         wxString::const_iterator i = target.end() - 1;
856         size_t new_len = target.length() - 1;
857 
858         for ( ; i != target.begin(); i-- )
859         {
860             if ( wxPGGetIterChar(target, i) != wxT('0') )
861                 break;
862             new_len--;
863         }
864 
865         wxChar cur_char = wxPGGetIterChar(target, i);
866         if ( cur_char != wxT('.') && cur_char != wxT(',') )
867             new_len++;
868 
869         if ( new_len != target.length() )
870             target.resize(new_len);
871     }
872 }
873 
GetValueAsString(int argFlags) const874 wxString wxFloatProperty::GetValueAsString( int argFlags ) const
875 {
876     wxString text;
877     if ( !m_value.IsNull() )
878     {
879         wxPropertyGrid::DoubleToString(text,
880                                        m_value,
881                                        m_precision,
882                                        !(argFlags & wxPG_FULL_VALUE),
883                                        (wxString*) NULL);
884     }
885     return text;
886 }
887 
StringToValue(wxVariant & variant,const wxString & text,int argFlags) const888 bool wxFloatProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
889 {
890     wxString s;
891     double value;
892 
893     if ( text.length() == 0 )
894     {
895         variant.MakeNull();
896         return true;
897     }
898 
899     bool res = text.ToDouble(&value);
900     if ( res )
901     {
902         if ( m_value.IsNull() || m_value != value )
903         {
904             variant = value;
905             return true;
906         }
907     }
908     else if ( argFlags & wxPG_REPORT_ERROR )
909     {
910     }
911     return false;
912 }
913 
DoValidation(const wxPGProperty * property,double & value,wxPGValidationInfo * pValidationInfo,int mode)914 bool wxFloatProperty::DoValidation( const wxPGProperty* property, double& value, wxPGValidationInfo* pValidationInfo, int mode )
915 {
916     // Check for min/max
917     double min = (double)wxINT64_MIN;
918     double max = (double)wxINT64_MAX;
919     wxVariant variant;
920     bool minOk = false;
921     bool maxOk = false;
922 
923     variant = property->GetAttribute(wxPGGlobalVars->m_strMin);
924     if ( !variant.IsNull() )
925     {
926         wxPGVariantToDouble(variant, &min);
927         minOk = true;
928     }
929 
930     variant = property->GetAttribute(wxPGGlobalVars->m_strMax);
931     if ( !variant.IsNull() )
932     {
933         wxPGVariantToDouble(variant, &max);
934         maxOk = true;
935     }
936 
937     if ( minOk )
938     {
939         if ( value < min )
940         {
941             if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
942                 pValidationInfo->m_failureMessage = wxString::Format(_("Value must be %f or higher"),min);
943             else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
944                 value = min;
945             else
946                 value = max - (min - value);
947             return false;
948         }
949     }
950 
951     if ( maxOk )
952     {
953         wxPGVariantToDouble(variant, &max);
954         if ( value > max )
955         {
956             if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
957                 pValidationInfo->m_failureMessage = wxString::Format(_("Value must be %f or less"),max);
958             else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
959                 value = max;
960             else
961                 value = min + (value - max);
962             return false;
963         }
964     }
965     return true;
966 }
967 
ValidateValue(wxVariant & value,wxPGValidationInfo & validationInfo) const968 bool wxFloatProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const
969 {
970     double fpv;
971     if ( wxPGVariantToDouble(value, &fpv) )
972         return DoValidation(this, fpv, &validationInfo, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
973     return true;
974 }
975 
DoSetAttribute(const wxString & name,wxVariant & value)976 bool wxFloatProperty::DoSetAttribute( const wxString& name, wxVariant& value )
977 {
978     if ( name == wxPG_FLOAT_PRECISION )
979     {
980         m_precision = value.GetLong();
981         return true;
982     }
983     return false;
984 }
985 
986 wxValidator*
GetClassValidator()987 wxFloatProperty::GetClassValidator()
988 {
989 #if wxUSE_VALIDATORS
990     WX_PG_DOGETVALIDATOR_ENTRY()
991 
992     wxValidator* validator = new wxNumericPropertyValidator(
993                                     wxNumericPropertyValidator::Float);
994 
995     WX_PG_DOGETVALIDATOR_EXIT(validator)
996 #else
997     return NULL;
998 #endif
999 }
1000 
DoGetValidator() const1001 wxValidator* wxFloatProperty::DoGetValidator() const
1002 {
1003     return GetClassValidator();
1004 }
1005 
1006 // -----------------------------------------------------------------------
1007 // wxBoolProperty
1008 // -----------------------------------------------------------------------
1009 
1010 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
1011 // there is a custom GetEditorClass.
1012 
IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty,wxPGProperty) const1013 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty, wxPGProperty)
1014 
1015 const wxPGEditor* wxBoolProperty::DoGetEditorClass() const
1016 {
1017     // Select correct editor control.
1018 #if wxPG_INCLUDE_CHECKBOX
1019     if ( !(m_flags & wxPG_PROP_USE_CHECKBOX) )
1020         return wxPG_EDITOR(Choice);
1021     return wxPG_EDITOR(CheckBox);
1022 #else
1023     return wxPG_EDITOR(Choice);
1024 #endif
1025 }
1026 
wxBoolProperty(const wxString & label,const wxString & name,bool value)1027 wxBoolProperty::wxBoolProperty( const wxString& label, const wxString& name, bool value ) :
1028     wxPGProperty(label,name)
1029 {
1030     SetValue(wxPGVariant_Bool(value));
1031 
1032     m_flags |= wxPG_PROP_USE_DCC;
1033 }
1034 
~wxBoolProperty()1035 wxBoolProperty::~wxBoolProperty() { }
1036 
GetValueAsString(int argFlags) const1037 wxString wxBoolProperty::GetValueAsString( int argFlags ) const
1038 {
1039     bool value = m_value.GetBool();
1040 
1041     // As a fragment of composite string value,
1042     // make it a little more readable.
1043     if ( argFlags & wxPG_COMPOSITE_FRAGMENT )
1044     {
1045         if ( value )
1046         {
1047             return m_label;
1048         }
1049         else
1050         {
1051             if ( argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT )
1052                 return wxEmptyString;
1053 
1054             const wxChar* notFmt;
1055             if ( wxPGGlobalVars->m_autoGetTranslation )
1056                 notFmt = _("Not %s");
1057             else
1058                 notFmt = wxT("Not %s");
1059 
1060             return wxString::Format(notFmt,m_label.c_str());
1061         }
1062     }
1063 
1064     if ( !(argFlags & wxPG_FULL_VALUE) )
1065     {
1066         return wxPGGlobalVars->m_boolChoices[value?1:0].GetText();
1067     }
1068 
1069     wxString text;
1070 
1071     if (value) text = wxT("true");
1072     else text = wxT("false");
1073 
1074     return text;
1075 }
1076 
GetChoiceInfo(wxPGChoiceInfo * choiceinfo)1077 int wxBoolProperty::GetChoiceInfo( wxPGChoiceInfo* choiceinfo )
1078 {
1079     if ( choiceinfo )
1080         choiceinfo->m_choices = &wxPGGlobalVars->m_boolChoices;
1081 
1082     if ( IsValueUnspecified() )
1083         return -1;
1084 
1085     return m_value.GetBool()?1:0;
1086 }
1087 
StringToValue(wxVariant & variant,const wxString & text,int WXUNUSED (argFlags)) const1088 bool wxBoolProperty::StringToValue( wxVariant& variant, const wxString& text, int WXUNUSED(argFlags) ) const
1089 {
1090     int value = 0;
1091     if ( text.CmpNoCase(wxPGGlobalVars->m_boolChoices[1].GetText()) == 0 ||
1092          text.CmpNoCase(wxT("true")) == 0 ||
1093          text.CmpNoCase(m_label) == 0 )
1094         value = 1;
1095 
1096     if ( text.length() == 0 )
1097     {
1098         variant.MakeNull();
1099         return true;
1100     }
1101 
1102     if ( m_value.IsNull() || (m_value.GetBool() && !value) || (!m_value.GetBool() && value) )
1103     {
1104         variant = wxPGVariant_Bool(value);
1105         return true;
1106     }
1107     return false;
1108 }
1109 
IntToValue(wxVariant & variant,int value,int) const1110 bool wxBoolProperty::IntToValue( wxVariant& variant, int value, int ) const
1111 {
1112     bool boolValue = value ? true : false;
1113 
1114     if ( m_value.IsNull() || boolValue != m_value.GetBool() )
1115     {
1116         variant = wxPGVariant_Bool(boolValue);
1117         return true;
1118     }
1119     return false;
1120 }
1121 
DoSetAttribute(const wxString & name,wxVariant & value)1122 bool wxBoolProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1123 {
1124 #if wxPG_INCLUDE_CHECKBOX
1125     if ( name == wxPG_BOOL_USE_CHECKBOX )
1126     {
1127         int ival = wxPGVariantToInt(value);
1128         if ( ival )
1129             m_flags |= wxPG_PROP_USE_CHECKBOX;
1130         else
1131             m_flags &= ~(wxPG_PROP_USE_CHECKBOX);
1132         return true;
1133     }
1134 #endif
1135     if ( name == wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING )
1136     {
1137         int ival = wxPGVariantToInt(value);
1138         if ( ival )
1139             m_flags |= wxPG_PROP_USE_DCC;
1140         else
1141             m_flags &= ~(wxPG_PROP_USE_DCC);
1142         return true;
1143     }
1144     return false;
1145 }
1146 
1147 // -----------------------------------------------------------------------
1148 // wxBaseEnumProperty
1149 // -----------------------------------------------------------------------
1150 
1151 int wxBaseEnumProperty::ms_nextIndex = -2;
1152 
wxBaseEnumProperty(const wxString & label,const wxString & name)1153 wxBaseEnumProperty::wxBaseEnumProperty( const wxString& label, const wxString& name )
1154     : wxPGProperty(label,name)
1155 {
1156     m_value = wxPGVariant_Zero;
1157 }
1158 
1159 /** If has values array, then returns number at index with value -
1160     otherwise just returns the value.
1161 */
GetIndexForValue(int value) const1162 int wxBaseEnumProperty::GetIndexForValue( int value ) const
1163 {
1164     return value;
1165 }
1166 
OnSetValue()1167 void wxBaseEnumProperty::OnSetValue()
1168 {
1169     if ( wxPGIsVariantType(m_value, long) )
1170         ValueFromInt_( m_value, m_value.GetLong(), wxPG_FULL_VALUE );
1171     else if ( wxPGIsVariantType(m_value, string) )
1172         ValueFromString_( m_value, m_value.GetString(), 0 );
1173     else
1174     // C::B patch: Fix compiler warning
1175     {   wxASSERT( false ); }
1176 
1177     if ( ms_nextIndex != -2 )
1178     {
1179         m_index = ms_nextIndex;
1180         ms_nextIndex = -2;
1181     }
1182 }
1183 
ValidateValue(wxVariant & value,wxPGValidationInfo & WXUNUSED (validationInfo)) const1184 bool wxBaseEnumProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& WXUNUSED(validationInfo) ) const
1185 {
1186     // Make sure string value is in the list,
1187     // unless property has string as preferred value type
1188     // To reduce code size, use conversion here as well
1189     if ( wxPGIsVariantType(value, string) &&
1190          !this->IsKindOf(CLASSINFO(wxEditEnumProperty)) )
1191         return ValueFromString_( value, value.GetString(), wxPG_PROPERTY_SPECIFIC );
1192 
1193     return true;
1194 }
1195 
GetValueAsString(int) const1196 wxString wxBaseEnumProperty::GetValueAsString( int ) const
1197 {
1198     if ( wxPGIsVariantType(m_value, string) )
1199         return m_value.GetString();
1200 
1201     if ( m_index >= 0 )
1202     {
1203         int unusedVal;
1204         const wxString* pstr = GetEntry( m_index, &unusedVal );
1205 
1206         if ( pstr )
1207             return *pstr;
1208     }
1209     return wxEmptyString;
1210 }
1211 
StringToValue(wxVariant & variant,const wxString & text,int argFlags) const1212 bool wxBaseEnumProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
1213 {
1214     return ValueFromString_( variant, text, argFlags );
1215 }
1216 
IntToValue(wxVariant & variant,int intVal,int argFlags) const1217 bool wxBaseEnumProperty::IntToValue( wxVariant& variant, int intVal, int argFlags ) const
1218 {
1219     return ValueFromInt_( variant, intVal, argFlags );
1220 }
1221 
ValueFromString_(wxVariant & value,const wxString & text,int argFlags) const1222 bool wxBaseEnumProperty::ValueFromString_( wxVariant& value, const wxString& text, int argFlags ) const
1223 {
1224     size_t i = 0;
1225     const wxString* entryLabel;
1226     int entryValue;
1227     int useIndex = -1;
1228     long useValue = 0;
1229 
1230     entryLabel = GetEntry(i, &entryValue);
1231     while ( entryLabel )
1232     {
1233         if ( text.CmpNoCase(*entryLabel) == 0 )
1234         {
1235             useIndex = (int)i;
1236             useValue = (long)entryValue;
1237             break;
1238         }
1239 
1240         i++;
1241         entryLabel = GetEntry(i, &entryValue);
1242     }
1243 
1244     bool asText = false;
1245 
1246     bool isEdit = this->IsKindOf(CLASSINFO(wxEditEnumProperty));
1247 
1248     // If text not any of the choices, store as text instead
1249     // (but only if we are wxEditEnumProperty)
1250     if ( useIndex == -1 &&
1251          isEdit )
1252     {
1253         asText = true;
1254     }
1255 
1256     int setAsNextIndex = -2;
1257     int curIndex = GetIndex();
1258 
1259     if ( asText )
1260     {
1261         setAsNextIndex = -1;
1262         value = text;
1263     }
1264     else if ( curIndex != useIndex )
1265     {
1266         if ( useIndex != -1 )
1267         {
1268             setAsNextIndex = useIndex;
1269             value = (long)useValue;
1270         }
1271         else
1272         {
1273             setAsNextIndex = -1;
1274             value = wxPGVariant_MinusOne;
1275         }
1276     }
1277 
1278     if ( setAsNextIndex != -2 )
1279     {
1280         // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1281         // validation purposes only, and index must not be changed
1282         if ( !(argFlags & wxPG_PROPERTY_SPECIFIC) )
1283             ms_nextIndex = setAsNextIndex;
1284 
1285         if ( isEdit || setAsNextIndex != -1 )
1286             return true;
1287         else
1288             return false;
1289     }
1290     return false;
1291 }
1292 
ValueFromInt_(wxVariant & variant,int intVal,int argFlags) const1293 bool wxBaseEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argFlags ) const
1294 {
1295     // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1296     //
1297     int curIndex = GetIndex();
1298     ms_nextIndex = -2;
1299 
1300     if ( argFlags & wxPG_FULL_VALUE )
1301     {
1302         ms_nextIndex = GetIndexForValue( intVal );
1303     }
1304     else
1305     {
1306         if ( curIndex != intVal )
1307         {
1308             ms_nextIndex = intVal;
1309         }
1310     }
1311 
1312     if ( ms_nextIndex != -2 )
1313     {
1314         if ( !(argFlags & wxPG_FULL_VALUE) )
1315             GetEntry(intVal, &intVal);
1316 
1317         variant = (long)intVal;
1318 
1319         return true;
1320     }
1321 
1322     return false;
1323 }
1324 
1325 void
OnValidationFailure(wxVariant & WXUNUSED (pendingValue))1326 wxBaseEnumProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) )
1327 {
1328     // Revert index
1329     ResetNextIndex();
1330 }
1331 
SetIndex(int index)1332 void wxBaseEnumProperty::SetIndex( int index )
1333 {
1334     ms_nextIndex = -2;
1335     m_index = index;
1336 }
1337 
GetIndex() const1338 int wxBaseEnumProperty::GetIndex() const
1339 {
1340     if ( m_value.IsNull() )
1341         return -1;
1342 
1343     if ( ms_nextIndex != -2 )
1344         return ms_nextIndex;
1345 
1346     return m_index;
1347 }
1348 
1349 // -----------------------------------------------------------------------
1350 // wxEnumProperty
1351 // -----------------------------------------------------------------------
1352 
IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty,wxPGProperty)1353 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty, wxPGProperty)
1354 
1355 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty,long,Choice)
1356 
1357 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
1358     const long* values, int value ) : wxBaseEnumProperty(label,name)
1359 {
1360     SetIndex(0);
1361 
1362     if ( labels )
1363     {
1364         m_choices.Add(labels,values);
1365 
1366         if ( GetItemCount() )
1367             SetValue( (long)value );
1368     }
1369 }
1370 
wxEnumProperty(const wxString & label,const wxString & name,const wxChar ** labels,const long * values,wxPGChoices * choicesCache,int value)1371 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
1372     const long* values, wxPGChoices* choicesCache, int value )
1373     : wxBaseEnumProperty(label,name)
1374 {
1375     SetIndex(0);
1376 
1377     wxASSERT( choicesCache );
1378 
1379     if ( choicesCache->IsOk() )
1380     {
1381         m_choices.Assign( *choicesCache );
1382         m_value = wxPGVariant_Zero;
1383     }
1384     else if ( labels )
1385     {
1386         m_choices.Add(labels,values);
1387 
1388         if ( GetItemCount() )
1389             SetValue( (long)value );
1390     }
1391 }
1392 
wxEnumProperty(const wxString & label,const wxString & name,const wxArrayString & labels,const wxArrayInt & values,int value)1393 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
1394     const wxArrayString& labels, const wxArrayInt& values, int value ) : wxBaseEnumProperty(label,name)
1395 {
1396     SetIndex(0);
1397 
1398     if ( labels.size() )
1399     {
1400         m_choices.Set(labels, values);
1401 
1402         if ( GetItemCount() )
1403             SetValue( (long)value );
1404     }
1405 }
1406 
wxEnumProperty(const wxString & label,const wxString & name,wxPGChoices & choices,int value)1407 wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
1408     wxPGChoices& choices, int value )
1409     : wxBaseEnumProperty(label,name)
1410 {
1411     m_choices.Assign( choices );
1412 
1413     if ( GetItemCount() )
1414         SetValue( (long)value );
1415 }
1416 
GetIndexForValue(int value) const1417 int wxEnumProperty::GetIndexForValue( int value ) const
1418 {
1419     if ( !m_choices.IsOk() )
1420         return -1;
1421 
1422     int intVal = m_choices.Index(value);
1423     if ( intVal >= 0 )
1424         return intVal;
1425 
1426     return value;
1427 }
1428 
~wxEnumProperty()1429 wxEnumProperty::~wxEnumProperty ()
1430 {
1431 }
1432 
GetEntry(size_t index,int * pvalue) const1433 const wxString* wxEnumProperty::GetEntry( size_t index, int* pvalue ) const
1434 {
1435     if ( m_choices.IsOk() && index < m_choices.GetCount() )
1436     {
1437         int value = m_choices.GetValue(index);
1438 
1439         if ( pvalue )
1440             *pvalue = value;
1441 
1442         return &m_choices.GetLabel(index);
1443     }
1444     return (const wxString*) NULL;
1445 }
1446 
GetChoiceInfo(wxPGChoiceInfo * choiceinfo)1447 int wxEnumProperty::GetChoiceInfo( wxPGChoiceInfo* choiceinfo )
1448 {
1449     if ( choiceinfo )
1450         choiceinfo->m_choices = &m_choices;
1451 
1452     if ( !m_choices.IsOk() )
1453         return -1;
1454 
1455     return GetIndex();
1456 }
1457 
1458 // -----------------------------------------------------------------------
1459 // wxEditEnumProperty
1460 // -----------------------------------------------------------------------
1461 
IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty,wxPGProperty)1462 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty, wxPGProperty)
1463 
1464 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty,wxString,ComboBox)
1465 
1466 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
1467     const long* values, const wxString& value )
1468     : wxEnumProperty(label,name,labels,values,0)
1469 {
1470     SetValue( value );
1471 }
1472 
wxEditEnumProperty(const wxString & label,const wxString & name,const wxChar ** labels,const long * values,wxPGChoices * choicesCache,const wxString & value)1473 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
1474     const long* values, wxPGChoices* choicesCache, const wxString& value )
1475     : wxEnumProperty(label,name,labels,values,choicesCache,0)
1476 {
1477     SetValue( value );
1478 }
1479 
wxEditEnumProperty(const wxString & label,const wxString & name,const wxArrayString & labels,const wxArrayInt & values,const wxString & value)1480 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name,
1481     const wxArrayString& labels, const wxArrayInt& values, const wxString& value )
1482     : wxEnumProperty(label,name,labels,values,0)
1483 {
1484     SetValue( value );
1485 }
1486 
wxEditEnumProperty(const wxString & label,const wxString & name,wxPGChoices & choices,const wxString & value)1487 wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name,
1488     wxPGChoices& choices, const wxString& value )
1489     : wxEnumProperty(label,name,choices,0)
1490 {
1491     SetValue( value );
1492 }
1493 
~wxEditEnumProperty()1494 wxEditEnumProperty::~wxEditEnumProperty()
1495 {
1496 }
1497 
1498 // -----------------------------------------------------------------------
1499 // wxFlagsProperty
1500 // -----------------------------------------------------------------------
1501 
IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty,wxPGProperty)1502 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty,wxPGProperty)
1503 
1504 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty,long,TextCtrl)
1505 
1506 void wxFlagsProperty::Init()
1507 {
1508     SetFlag(wxPG_PROP_AGGREGATE);  // This is must be done here to support flag props
1509                                    // with inital zero children.
1510 
1511     long value = m_value;
1512 
1513     //
1514     // Generate children
1515     //
1516     unsigned int i;
1517 
1518     unsigned int prevChildCount = m_children.GetCount();
1519 
1520     int oldSel = -1;
1521     if ( prevChildCount )
1522     {
1523         wxPropertyGridState* state = GetParentState();
1524 
1525         // State safety check (it may be NULL in immediate parent)
1526         wxASSERT( state );
1527 
1528         if ( state )
1529         {
1530             wxPGProperty* selected = state->GetSelection();
1531             if ( selected )
1532             {
1533                 if ( selected->GetParent() == this )
1534                     oldSel = selected->GetArrIndex();
1535                 else if ( selected == this )
1536                     oldSel = -2;
1537             }
1538         }
1539         state->DoClearSelection();
1540     }
1541 
1542     // Delete old children
1543     for ( i=0; i<prevChildCount; i++ )
1544         delete ( (wxPGProperty*) m_children[i] );
1545 
1546     m_children.Empty();
1547 
1548     if ( m_choices.IsOk() )
1549     {
1550         const wxPGChoices& choices = m_choices;
1551 
1552         for ( i=0; i<GetItemCount(); i++ )
1553         {
1554             bool child_val = ( value & choices.GetValue(i) )?true:false;
1555 
1556             wxPGProperty* boolProp;
1557 
1558         #if wxUSE_INTL
1559             if ( wxPGGlobalVars->m_autoGetTranslation )
1560             {
1561                 boolProp = new wxBoolProperty( ::wxGetTranslation( GetLabel(i) ), wxPG_LABEL, child_val );
1562             }
1563             else
1564         #endif
1565             {
1566                 boolProp = new wxBoolProperty( GetLabel(i), wxPG_LABEL, child_val );
1567             }
1568             AddPrivateChild(boolProp);
1569         }
1570 
1571         m_oldChoicesData = m_choices.GetDataPtr();
1572     }
1573 
1574     m_oldValue = m_value;
1575 
1576     if ( prevChildCount )
1577         SubPropsChanged(oldSel);
1578 }
1579 
wxFlagsProperty(const wxString & label,const wxString & name,const wxChar ** labels,const long * values,long value)1580 wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1581     const wxChar** labels, const long* values, long value ) : wxPGProperty(label,name)
1582 {
1583     m_oldChoicesData = (wxPGChoicesData*) NULL;
1584 
1585     if ( labels )
1586     {
1587         m_choices.Set(labels,values);
1588 
1589         wxASSERT( GetItemCount() );
1590 
1591         SetValue( value );
1592     }
1593     else
1594     {
1595         m_value = wxPGVariant_Zero;
1596     }
1597 }
1598 
wxFlagsProperty(const wxString & label,const wxString & name,const wxArrayString & labels,const wxArrayInt & values,int value)1599 wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1600         const wxArrayString& labels, const wxArrayInt& values, int value )
1601     : wxPGProperty(label,name)
1602 {
1603     m_oldChoicesData = (wxPGChoicesData*) NULL;
1604 
1605     if ( labels.size() )
1606     {
1607         m_choices.Set(labels,values);
1608 
1609         wxASSERT( GetItemCount() );
1610 
1611         SetValue( (long)value );
1612     }
1613     else
1614     {
1615         m_value = wxPGVariant_Zero;
1616     }
1617 }
1618 
wxFlagsProperty(const wxString & label,const wxString & name,wxPGChoices & choices,long value)1619 wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
1620     wxPGChoices& choices, long value )
1621     : wxPGProperty(label,name)
1622 {
1623     m_oldChoicesData = (wxPGChoicesData*) NULL;
1624 
1625     if ( choices.IsOk() )
1626     {
1627         m_choices.Assign(choices);
1628 
1629         wxASSERT( GetItemCount() );
1630 
1631         SetValue( value );
1632     }
1633     else
1634     {
1635         m_value = wxPGVariant_Zero;
1636     }
1637 }
1638 
~wxFlagsProperty()1639 wxFlagsProperty::~wxFlagsProperty()
1640 {
1641 }
1642 
OnSetValue()1643 void wxFlagsProperty::OnSetValue()
1644 {
1645     if ( !m_choices.IsOk() || !GetItemCount() )
1646     {
1647         m_value = wxPGVariant_Zero;
1648     }
1649     else
1650     {
1651         long val = m_value.GetLong();
1652 
1653         long fullFlags = 0;
1654 
1655         // normalize the value (i.e. remove extra flags)
1656         unsigned int i;
1657         const wxPGChoices& choices = m_choices;
1658         for ( i = 0; i < GetItemCount(); i++ )
1659         {
1660             fullFlags |= choices.GetValue(i);
1661         }
1662 
1663         val &= fullFlags;
1664 
1665         m_value = val;
1666 
1667         // Need to (re)init now?
1668         if ( GetCount() != GetItemCount() ||
1669              m_choices.GetDataPtr() != m_oldChoicesData )
1670         {
1671             Init();
1672         }
1673     }
1674 
1675     long newFlags = m_value;
1676 
1677     if ( newFlags != m_oldValue )
1678     {
1679         // Set child modified states
1680         unsigned int i;
1681         const wxPGChoices& choices = m_choices;
1682         for ( i = 0; i<GetItemCount(); i++ )
1683         {
1684             int flag;
1685 
1686             flag = choices.GetValue(i);
1687 
1688             if ( (newFlags & flag) != (m_oldValue & flag) )
1689                 Item(i)->SetFlag( wxPG_PROP_MODIFIED );
1690         }
1691 
1692         m_oldValue = newFlags;
1693     }
1694 }
1695 
GetValueAsString(int) const1696 wxString wxFlagsProperty::GetValueAsString( int ) const
1697 {
1698     wxString text;
1699 
1700     if ( !m_choices.IsOk() )
1701         return text;
1702 
1703     long flags = m_value;
1704     unsigned int i;
1705     const wxPGChoices& choices = m_choices;
1706 
1707     for ( i = 0; i < GetItemCount(); i++ )
1708     {
1709         int doAdd;
1710 /* C::B begin */
1711         doAdd = ( (flags & choices.GetValue(i)) == choices.GetValue(i) );
1712 /* C::B end */
1713 
1714         if ( doAdd )
1715         {
1716             text += choices.GetLabel(i);
1717             text += wxT(", ");
1718         }
1719     }
1720 
1721     // remove last comma
1722     if ( text.Len() > 1 )
1723         text.Truncate ( text.Len() - 2 );
1724 
1725     return text;
1726 }
1727 
1728 // Translate string into flag tokens
StringToValue(wxVariant & variant,const wxString & text,int) const1729 bool wxFlagsProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
1730 {
1731     if ( !m_choices.IsOk() )
1732         return false;
1733 
1734     long newFlags = 0;
1735 
1736     // semicolons are no longer valid delimeters
1737     WX_PG_TOKENIZER1_BEGIN(text,wxT(','))
1738 
1739         if ( token.length() )
1740         {
1741             // Determine which one it is
1742             long bit = IdToBit( token );
1743 
1744             if ( bit != -1 )
1745             {
1746                 // Changed?
1747                 newFlags |= bit;
1748             }
1749             else
1750             {
1751                 break;
1752             }
1753         }
1754 
1755     WX_PG_TOKENIZER1_END()
1756 
1757     variant = newFlags;
1758 
1759     if ( m_value.IsNull() || newFlags != m_value.GetLong() )
1760         return true;
1761 
1762     return false;
1763 }
1764 
1765 // Converts string id to a relevant bit.
IdToBit(const wxString & id) const1766 long wxFlagsProperty::IdToBit( const wxString& id ) const
1767 {
1768     unsigned int i;
1769     for ( i = 0; i < GetItemCount(); i++ )
1770     {
1771         if ( id == GetLabel(i) )
1772         {
1773             return m_choices.GetValue(i);
1774         }
1775     }
1776     return -1;
1777 }
1778 
RefreshChildren()1779 void wxFlagsProperty::RefreshChildren()
1780 {
1781     if ( !m_choices.IsOk() || !GetCount() ) return;
1782 
1783     int flags = m_value.GetLong();
1784 
1785     const wxPGChoices& choices = m_choices;
1786     unsigned int i;
1787     for ( i = 0; i < GetItemCount(); i++ )
1788     {
1789         long flag;
1790 
1791         flag = choices.GetValue(i);
1792 
1793         long subVal = flags & flag;
1794         wxPGProperty* p = Item(i);
1795 
1796         if ( subVal != (m_oldValue & flag) )
1797             p->SetFlag( wxPG_PROP_MODIFIED );
1798 
1799 /* C::B begin */
1800         p->SetValue( subVal==flag?true:false );
1801 /* C::B end */
1802     }
1803 
1804     m_oldValue = flags;
1805 }
1806 
ChildChanged(wxVariant & thisValue,int childIndex,wxVariant & childValue) const1807 void wxFlagsProperty::ChildChanged( wxVariant& thisValue, int childIndex, wxVariant& childValue ) const
1808 {
1809     long oldValue = thisValue.GetLong();
1810     long val = childValue.GetLong();
1811     unsigned long vi = m_choices.GetValue(childIndex);
1812     if ( val )
1813         thisValue = (long)(oldValue | vi);
1814     else
1815         thisValue = (long)(oldValue & ~(vi));
1816 }
1817 
GetChoiceInfo(wxPGChoiceInfo * choiceinfo)1818 int wxFlagsProperty::GetChoiceInfo( wxPGChoiceInfo* choiceinfo )
1819 {
1820     if ( choiceinfo )
1821         choiceinfo->m_choices = &m_choices;
1822     return -1;
1823 }
1824 
1825 // -----------------------------------------------------------------------
1826 // wxDirProperty
1827 // -----------------------------------------------------------------------
1828 
WX_PG_IMPLEMENT_DERIVED_PROPERTY_CLASS(wxDirProperty,wxLongStringProperty,const wxString &)1829 WX_PG_IMPLEMENT_DERIVED_PROPERTY_CLASS(wxDirProperty,wxLongStringProperty,const wxString&)
1830 
1831 wxDirProperty::wxDirProperty( const wxString& name, const wxString& label, const wxString& value )
1832   : wxLongStringProperty(name,label,value)
1833 {
1834     m_flags |= wxPG_NO_ESCAPE;
1835 }
~wxDirProperty()1836 wxDirProperty::~wxDirProperty() { }
1837 
DoGetValidator() const1838 wxValidator* wxDirProperty::DoGetValidator() const
1839 {
1840     return wxFileProperty::GetClassValidator();
1841 }
1842 
OnButtonClick(wxPropertyGrid * propGrid,wxString & value)1843 bool wxDirProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
1844 {
1845     wxSize dlg_sz(300,400);
1846 
1847     wxDirDialog dlg( propGrid,
1848                      m_dlgMessage.length() ? m_dlgMessage : wxString(_("Choose a directory:")),
1849                      value,
1850                      0,
1851 #if !wxPG_SMALL_SCREEN
1852                      propGrid->GetGoodEditorDialogPosition(this,dlg_sz),
1853                      dlg_sz );
1854 #else
1855                      wxDefaultPosition,
1856                      wxDefaultSize );
1857 #endif
1858 
1859     if ( dlg.ShowModal() == wxID_OK )
1860     {
1861         value = dlg.GetPath();
1862         return true;
1863     }
1864     return false;
1865 }
1866 
DoSetAttribute(const wxString & name,wxVariant & value)1867 bool wxDirProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1868 {
1869     if ( name == wxPG_DIR_DIALOG_MESSAGE )
1870     {
1871         m_dlgMessage = value.GetString();
1872         return true;
1873     }
1874     return false;
1875 }
1876 
1877 // -----------------------------------------------------------------------
1878 // wxPGFileDialogAdapter
1879 // -----------------------------------------------------------------------
1880 
DoShowDialog(wxPropertyGrid * propGrid,wxPGProperty * property)1881 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
1882 {
1883     wxFileProperty* fileProp = NULL;
1884     wxString path;
1885     int indFilter = -1;
1886 
1887     if ( property->IsKindOf(CLASSINFO(wxFileProperty)) )
1888     {
1889         fileProp = ((wxFileProperty*)property);
1890         path = fileProp->m_filename.GetPath();
1891         indFilter = fileProp->m_indFilter;
1892 
1893         if ( !path.length() && fileProp->m_basePath.length() )
1894             path = fileProp->m_basePath;
1895     }
1896     else
1897     {
1898         wxFileName fn(property->GetValue().GetString());
1899         path = fn.GetPath();
1900     }
1901 
1902     wxFileDialog dlg( propGrid->GetPanel(),
1903                       property->GetAttribute(wxT("DialogTitle"), _("Choose a file")),
1904                       property->GetAttribute(wxT("InitialPath"), path),
1905                       wxEmptyString,
1906                       property->GetAttribute(wxPG_FILE_WILDCARD, _("All files (*.*)|*.*")),
1907                       0,
1908                       wxDefaultPosition );
1909 
1910     if ( indFilter >= 0 )
1911         dlg.SetFilterIndex( indFilter );
1912 
1913     if ( dlg.ShowModal() == wxID_OK )
1914     {
1915         if ( fileProp )
1916             fileProp->m_indFilter = dlg.GetFilterIndex();
1917         SetValue( dlg.GetPath() );
1918         return true;
1919     }
1920     return false;
1921 }
1922 
1923 // -----------------------------------------------------------------------
1924 // wxFileProperty
1925 // -----------------------------------------------------------------------
1926 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty,wxPGProperty,wxString,const wxString &,TextCtrlAndButton)1927 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty,wxPGProperty,
1928                                wxString,const wxString&,TextCtrlAndButton)
1929 
1930 wxFileProperty::wxFileProperty( const wxString& label, const wxString& name,
1931     const wxString& value ) : wxPGProperty(label,name)
1932 {
1933     m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
1934     m_indFilter = -1;
1935     SetAttribute( wxPG_FILE_WILDCARD, _("All files (*.*)|*.*") );
1936 
1937     SetValue(value);
1938 }
1939 
~wxFileProperty()1940 wxFileProperty::~wxFileProperty() {}
1941 
1942 #if wxUSE_VALIDATORS
1943 
GetClassValidator()1944 wxValidator* wxFileProperty::GetClassValidator()
1945 {
1946     WX_PG_DOGETVALIDATOR_ENTRY()
1947 
1948     // Atleast wxPython 2.6.2.1 required that the string argument is given
1949     static wxString v;
1950     wxTextValidator* validator = new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST,&v);
1951 
1952     wxArrayString exChars;
1953     exChars.Add(wxT("?"));
1954     exChars.Add(wxT("*"));
1955     exChars.Add(wxT("|"));
1956     exChars.Add(wxT("<"));
1957     exChars.Add(wxT(">"));
1958     exChars.Add(wxT("\""));
1959 
1960     validator->SetExcludes(exChars);
1961 
1962     WX_PG_DOGETVALIDATOR_EXIT(validator)
1963 }
1964 
DoGetValidator() const1965 wxValidator* wxFileProperty::DoGetValidator() const
1966 {
1967     return GetClassValidator();
1968 }
1969 
1970 #endif
1971 
OnSetValue()1972 void wxFileProperty::OnSetValue()
1973 {
1974     const wxString& fnstr = m_value.GetString();
1975 
1976     m_filename = fnstr;
1977 
1978     if ( !m_filename.HasName() )
1979     {
1980         m_value = wxPGVariant_EmptyString;
1981         m_filename.Clear();
1982     }
1983 
1984     // Find index for extension.
1985     if ( m_indFilter < 0 && fnstr.length() )
1986     {
1987         wxString ext = m_filename.GetExt();
1988         int curind = 0;
1989         size_t pos = 0;
1990         size_t len = m_wildcard.length();
1991 
1992         pos = m_wildcard.find(wxT("|"), pos);
1993         while ( pos != wxString::npos && pos < (len-3) )
1994         {
1995             size_t ext_begin = pos + 3;
1996 
1997             pos = m_wildcard.find(wxT("|"), ext_begin);
1998             if ( pos == wxString::npos )
1999                 pos = len;
2000             wxString found_ext = m_wildcard.substr(ext_begin, pos-ext_begin);
2001 
2002             if ( found_ext.length() > 0 )
2003             {
2004                 if ( found_ext[0] == wxT('*') )
2005                 {
2006                     m_indFilter = curind;
2007                     break;
2008                 }
2009                 if ( ext.CmpNoCase(found_ext) == 0 )
2010                 {
2011                     m_indFilter = curind;
2012                     break;
2013                 }
2014             }
2015 
2016             if ( pos != len )
2017                 pos = m_wildcard.find(wxT("|"), pos+1);
2018 
2019             curind++;
2020         }
2021     }
2022 }
2023 
GetValueAsString(int argFlags) const2024 wxString wxFileProperty::GetValueAsString( int argFlags ) const
2025 {
2026     // Always return empty string when name component is empty
2027     wxString fullName = m_filename.GetFullName();
2028     if ( !fullName.length() )
2029         return fullName;
2030 
2031     if ( argFlags & wxPG_FULL_VALUE )
2032     {
2033         return m_filename.GetFullPath();
2034     }
2035     else if ( m_flags & wxPG_PROP_SHOW_FULL_FILENAME )
2036     {
2037         if ( m_basePath.Length() )
2038         {
2039             wxFileName fn2(m_filename);
2040             fn2.MakeRelativeTo(m_basePath);
2041             return fn2.GetFullPath();
2042         }
2043         return m_filename.GetFullPath();
2044     }
2045 
2046     return m_filename.GetFullName();
2047 }
2048 
GetEditorDialog() const2049 wxPGEditorDialogAdapter* wxFileProperty::GetEditorDialog() const
2050 {
2051     return new wxPGFileDialogAdapter();
2052 }
2053 
StringToValue(wxVariant & variant,const wxString & text,int argFlags) const2054 bool wxFileProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
2055 {
2056     if ( (m_flags & wxPG_PROP_SHOW_FULL_FILENAME) || (argFlags & wxPG_FULL_VALUE) )
2057     {
2058         if ( m_filename != text )
2059         {
2060             variant = text;
2061             return true;
2062         }
2063     }
2064     else
2065     {
2066         if ( m_filename.GetFullName() != text )
2067         {
2068             wxFileName fn = m_filename;
2069             fn.SetFullName(text);
2070             variant = fn.GetFullPath();
2071             return true;
2072         }
2073     }
2074 
2075     return false;
2076 }
2077 
DoSetAttribute(const wxString & name,wxVariant & value)2078 bool wxFileProperty::DoSetAttribute( const wxString& name, wxVariant& value )
2079 {
2080     // Return false on some occasions to make sure those attribs will get
2081     // stored in m_attributes.
2082     if ( name == wxPG_FILE_SHOW_FULL_PATH )
2083     {
2084         if ( wxPGVariantToInt(value) )
2085             m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
2086         else
2087             m_flags &= ~(wxPG_PROP_SHOW_FULL_FILENAME);
2088         return true;
2089     }
2090     else if ( name == wxPG_FILE_WILDCARD )
2091     {
2092         m_wildcard = value.GetString();
2093     }
2094     else if ( name == wxPG_FILE_SHOW_RELATIVE_PATH )
2095     {
2096         m_basePath = value.GetString();
2097 
2098         // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
2099         m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
2100     }
2101     else if ( name == wxPG_FILE_INITIAL_PATH )
2102     {
2103         m_initialPath = value.GetString();
2104         return true;
2105     }
2106     else if ( name == wxPG_FILE_DIALOG_TITLE )
2107     {
2108         m_dlgTitle = value.GetString();
2109         return true;
2110     }
2111     return false;
2112 }
2113 
2114 // -----------------------------------------------------------------------
2115 // wxPGLongStringDialogAdapter
2116 // -----------------------------------------------------------------------
2117 
DoShowDialog(wxPropertyGrid * propGrid,wxPGProperty * property)2118 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
2119 {
2120     wxString val1 = property->GetValueAsString(0);
2121     wxString val_orig = val1;
2122 
2123     wxString value;
2124     if ( !property->HasFlag(wxPG_PROP_NO_ESCAPE) )
2125         wxPropertyGrid::ExpandEscapeSequences(value, val1);
2126     else
2127         value = wxString(val1);
2128 
2129     // Run editor dialog.
2130     if ( wxLongStringProperty::DisplayEditorDialog(property, propGrid, value) )
2131     {
2132         if ( !property->HasFlag(wxPG_PROP_NO_ESCAPE) )
2133             wxPropertyGrid::CreateEscapeSequences(val1,value);
2134         else
2135             val1 = value;
2136 
2137         if ( val1 != val_orig )
2138         {
2139             SetValue( val1 );
2140             return true;
2141         }
2142     }
2143     return false;
2144 }
2145 
2146 // -----------------------------------------------------------------------
2147 // wxLongStringProperty
2148 // -----------------------------------------------------------------------
2149 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty,wxPGProperty,wxString,const wxString &,TextCtrlAndButton)2150 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty,wxPGProperty,
2151                                wxString,const wxString&,TextCtrlAndButton)
2152 
2153 wxLongStringProperty::wxLongStringProperty( const wxString& label, const wxString& name,
2154     const wxString& value ) : wxPGProperty(label,name)
2155 {
2156     SetValue(value);
2157 }
2158 
~wxLongStringProperty()2159 wxLongStringProperty::~wxLongStringProperty() {}
2160 
GetValueAsString(int) const2161 wxString wxLongStringProperty::GetValueAsString( int ) const
2162 {
2163     return m_value;
2164 }
2165 
OnEvent(wxPropertyGrid * propGrid,wxWindow * WXUNUSED (primary),wxEvent & event)2166 bool wxLongStringProperty::OnEvent( wxPropertyGrid* propGrid, wxWindow* WXUNUSED(primary),
2167                                     wxEvent& event )
2168 {
2169     if ( propGrid->IsMainButtonEvent(event) )
2170     {
2171         // Update the value
2172         PrepareValueForDialogEditing(propGrid);
2173 
2174         wxString val1 = GetValueAsString(0);
2175         wxString val_orig = val1;
2176 
2177         wxString value;
2178         if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
2179             wxPropertyGrid::ExpandEscapeSequences(value,val1);
2180         else
2181             value = wxString(val1);
2182 
2183         // Run editor dialog.
2184         if ( OnButtonClick(propGrid,value) )
2185         {
2186             if ( !(m_flags & wxPG_PROP_NO_ESCAPE) )
2187                 wxPropertyGrid::CreateEscapeSequences(val1,value);
2188             else
2189                 val1 = value;
2190 
2191             if ( val1 != val_orig )
2192             {
2193                 SetValueInEvent( val1 );
2194                 return true;
2195             }
2196         }
2197     }
2198     return false;
2199 }
2200 
OnButtonClick(wxPropertyGrid * propGrid,wxString & value)2201 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
2202 {
2203     return DisplayEditorDialog(this, propGrid, value);
2204 }
2205 
DisplayEditorDialog(wxPGProperty * prop,wxPropertyGrid * propGrid,wxString & value)2206 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty* prop, wxPropertyGrid* propGrid, wxString& value )
2207 
2208 {
2209     // launch editor dialog
2210     wxDialog* dlg = new wxDialog(propGrid,-1,prop->GetLabel(),wxDefaultPosition,wxDefaultSize,
2211                                  wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN);
2212 
2213     dlg->SetFont(propGrid->GetFont()); // To allow entering chars of the same set as the propGrid
2214 
2215     // Multi-line text editor dialog.
2216 #if !wxPG_SMALL_SCREEN
2217     const int spacing = 8;
2218 #else
2219     const int spacing = 4;
2220 #endif
2221     wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
2222     wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
2223     wxTextCtrl* ed = new wxTextCtrl(dlg,11,value,
2224         wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE);
2225 
2226     rowsizer->Add( ed, 1, wxEXPAND|wxALL, spacing );
2227     topsizer->Add( rowsizer, 1, wxEXPAND, 0 );
2228 
2229     wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
2230     buttonSizer->AddButton(new wxButton(dlg, wxID_OK));
2231     buttonSizer->AddButton(new wxButton(dlg, wxID_CANCEL));
2232     buttonSizer->Realize();
2233     topsizer->Add( buttonSizer, 0,
2234                    wxALIGN_RIGHT|wxBOTTOM|wxRIGHT,
2235                    spacing );
2236 
2237     dlg->SetSizer( topsizer );
2238     topsizer->SetSizeHints( dlg );
2239 
2240 #if !wxPG_SMALL_SCREEN
2241     dlg->SetSize(400,300);
2242 
2243     dlg->Move( propGrid->GetGoodEditorDialogPosition(prop,dlg->GetSize()) );
2244 #endif
2245 
2246     int res = dlg->ShowModal();
2247 
2248     if ( res == wxID_OK )
2249     {
2250         value = ed->GetValue();
2251         dlg->Destroy();
2252         return true;
2253     }
2254     dlg->Destroy();
2255     return false;
2256 }
2257 
StringToValue(wxVariant & variant,const wxString & text,int) const2258 bool wxLongStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
2259 {
2260     if ( m_value.IsNull() || m_value != text )
2261     {
2262         variant = text;
2263         return true;
2264     }
2265     return false;
2266 }
2267 
2268 // -----------------------------------------------------------------------
2269 // wxArrayEditorDialog
2270 // -----------------------------------------------------------------------
2271 
BEGIN_EVENT_TABLE(wxArrayEditorDialog,wxDialog)2272 BEGIN_EVENT_TABLE(wxArrayEditorDialog, wxDialog)
2273     EVT_IDLE(wxArrayEditorDialog::OnIdle)
2274     EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick)
2275     EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick)
2276     EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick)
2277     EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick)
2278     EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick)
2279     EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick)
2280     EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick)
2281     //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
2282 END_EVENT_TABLE()
2283 
2284 IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog, wxDialog)
2285 
2286 #include <wx/statline.h>
2287 
2288 // -----------------------------------------------------------------------
2289 
2290 void wxArrayEditorDialog::OnIdle(wxIdleEvent& event)
2291 {
2292     //
2293     // Do control focus detection here.
2294     //
2295 
2296     wxWindow* focused = FindFocus();
2297 
2298     // This strange focus thing is a workaround for wxGTK wxListBox focus
2299     // reporting bug.
2300     if ( m_curFocus == 0 && focused != m_edValue &&
2301          focused != m_butAdd && focused != m_butUpdate &&
2302          m_lbStrings->GetSelection() >= 0 )
2303     {
2304         // ListBox was just focused.
2305         m_butAdd->Enable(false);
2306         m_butUpdate->Enable(false);
2307         m_butRemove->Enable(true);
2308         m_butUp->Enable(true);
2309         m_butDown->Enable(true);
2310         m_curFocus = 1;
2311     }
2312     else if ( (m_curFocus == 1 && focused == m_edValue) /*|| m_curFocus == 2*/ )
2313     {
2314         // TextCtrl was just focused.
2315         m_butAdd->Enable(true);
2316         bool upd_enable = false;
2317         if ( m_lbStrings->GetCount() && m_lbStrings->GetSelection() >= 0 )
2318             upd_enable = true;
2319         m_butUpdate->Enable(upd_enable);
2320         m_butRemove->Enable(false);
2321         m_butUp->Enable(false);
2322         m_butDown->Enable(false);
2323         m_curFocus = 0;
2324     }
2325 
2326     event.Skip();
2327 }
2328 
2329 // -----------------------------------------------------------------------
2330 
wxArrayEditorDialog()2331 wxArrayEditorDialog::wxArrayEditorDialog()
2332     : wxDialog()
2333 {
2334     Init();
2335 }
2336 
2337 // -----------------------------------------------------------------------
2338 
Init()2339 void wxArrayEditorDialog::Init()
2340 {
2341     m_custBtText = (const wxChar*) NULL;
2342 #if defined(__WXPYTHON__)
2343     m_scriptObject = NULL;
2344 #endif
2345 }
2346 
2347 // -----------------------------------------------------------------------
2348 
wxArrayEditorDialog(wxWindow * parent,const wxString & message,const wxString & caption,long style,const wxPoint & pos,const wxSize & sz)2349 wxArrayEditorDialog::wxArrayEditorDialog( wxWindow *parent,
2350                                           const wxString& message,
2351                                           const wxString& caption,
2352                                           long style,
2353                                           const wxPoint& pos,
2354                                           const wxSize& sz )
2355     : wxDialog()
2356 {
2357     Init();
2358     Create(parent,message,caption,style,pos,sz);
2359 }
2360 
2361 // -----------------------------------------------------------------------
2362 
Create(wxWindow * parent,const wxString & message,const wxString & caption,long style,const wxPoint & pos,const wxSize & sz)2363 bool wxArrayEditorDialog::Create( wxWindow *parent,
2364                                   const wxString& message,
2365                                   const wxString& caption,
2366                                   long style,
2367                                   const wxPoint& pos,
2368                                   const wxSize& sz )
2369 {
2370     // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2371     // FIXME: This should be only a temporary fix.
2372 #ifdef __WXMAC__
2373     int useStyle = wxCAPTION;
2374 #else
2375     int useStyle = style;
2376 #endif
2377 
2378     bool res = wxDialog::Create(parent, wxID_ANY, caption, pos, sz, useStyle);
2379 
2380     SetFont(parent->GetFont()); // To allow entering chars of the same set as the propGrid
2381 
2382 #if !wxPG_SMALL_SCREEN
2383     const int spacing = 4;
2384 #else
2385     const int spacing = 3;
2386 #endif
2387 
2388     m_modified = false;
2389 
2390     m_curFocus = 1;
2391 
2392     wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
2393 
2394     // Message
2395     if ( message.length() )
2396         topsizer->Add( new wxStaticText(this,-1,message),
2397             0, wxALIGN_LEFT|wxALL, spacing );
2398 
2399     // String editor
2400     wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
2401     m_edValue = new wxTextCtrl(this,21,wxEmptyString,
2402         wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER);
2403     wxValidator* validator = GetTextCtrlValidator();
2404     if ( validator )
2405     {
2406         m_edValue->SetValidator( *validator );
2407         delete validator;
2408     }
2409     rowsizer->Add( m_edValue,
2410         1, wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
2411 
2412     // Add button
2413     m_butAdd = new wxButton(this,22,_("Add"));
2414     rowsizer->Add( m_butAdd,
2415         0, wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, spacing );
2416     topsizer->Add( rowsizer, 0, wxEXPAND, spacing );
2417 
2418     // Separator line
2419     topsizer->Add( new wxStaticLine(this,-1),
2420         0, wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT, spacing );
2421 
2422     rowsizer = new wxBoxSizer( wxHORIZONTAL );
2423 
2424     // list box
2425     m_lbStrings = new wxListBox(this, 24, wxDefaultPosition, wxDefaultSize);
2426     unsigned int i;
2427     for ( i=0; i<ArrayGetCount(); i++ )
2428         m_lbStrings->Append( ArrayGet(i) );
2429     rowsizer->Add( m_lbStrings, 1, wxEXPAND|wxRIGHT, spacing );
2430 
2431     // Manipulator buttons
2432     wxBoxSizer* colsizer = new wxBoxSizer( wxVERTICAL );
2433     m_butCustom = (wxButton*) NULL;
2434     if ( m_custBtText )
2435     {
2436         m_butCustom = new wxButton(this,28,::wxGetTranslation(m_custBtText));
2437         colsizer->Add( m_butCustom,
2438             0, wxALIGN_CENTER_HORIZONTAL|wxTOP/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
2439             spacing );
2440     }
2441     m_butUpdate = new wxButton(this,27,_("Update"));
2442     colsizer->Add( m_butUpdate,
2443         0, wxALIGN_CENTER_HORIZONTAL|wxTOP, spacing );
2444     m_butRemove = new wxButton(this,23,_("Remove"));
2445     colsizer->Add( m_butRemove,
2446         0, wxALIGN_CENTER_HORIZONTAL|wxTOP, spacing );
2447     m_butUp = new wxButton(this,25,_("Up"));
2448     colsizer->Add( m_butUp,
2449         0, wxALIGN_CENTER_HORIZONTAL|wxTOP, spacing );
2450     m_butDown = new wxButton(this,26,_("Down"));
2451     colsizer->Add( m_butDown,
2452         0, wxALIGN_CENTER_HORIZONTAL|wxTOP, spacing );
2453     rowsizer->Add( colsizer, 0, 0, spacing );
2454 
2455     topsizer->Add( rowsizer, 1, wxLEFT|wxRIGHT|wxEXPAND, spacing );
2456 
2457     // Separator line
2458     topsizer->Add( new wxStaticLine(this,-1),
2459         0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, spacing );
2460 
2461     // Standard dialog buttons
2462     wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
2463     buttonSizer->AddButton(new wxButton(this, wxID_OK));
2464     buttonSizer->AddButton(new wxButton(this, wxID_CANCEL));
2465     buttonSizer->Realize();
2466     topsizer->Add( buttonSizer, 0,
2467                    wxALIGN_RIGHT|wxALL,
2468                    spacing );
2469 
2470     m_edValue->SetFocus();
2471 
2472     SetSizer( topsizer );
2473     topsizer->SetSizeHints( this );
2474 
2475 #if !wxPG_SMALL_SCREEN
2476     if ( sz.x == wxDefaultSize.x &&
2477          sz.y == wxDefaultSize.y )
2478         SetSize( wxSize(275,360) );
2479     else
2480         SetSize(sz);
2481 #endif
2482 
2483     return res;
2484 }
2485 
2486 // -----------------------------------------------------------------------
2487 
OnAddClick(wxCommandEvent &)2488 void wxArrayEditorDialog::OnAddClick(wxCommandEvent& )
2489 {
2490     wxString text = m_edValue->GetValue();
2491     if ( text.length() )
2492     {
2493         if ( ArrayInsert( text, -1 ) )
2494         {
2495             m_lbStrings->Append( text );
2496             m_modified = true;
2497             m_edValue->Clear();
2498         }
2499     }
2500 }
2501 
2502 // -----------------------------------------------------------------------
2503 
OnDeleteClick(wxCommandEvent &)2504 void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent& )
2505 {
2506     int index = m_lbStrings->GetSelection();
2507     if ( index >= 0 )
2508     {
2509         ArrayRemoveAt( index );
2510         m_lbStrings->Delete ( index );
2511         m_modified = true;
2512     }
2513 }
2514 
2515 // -----------------------------------------------------------------------
2516 
OnUpClick(wxCommandEvent &)2517 void wxArrayEditorDialog::OnUpClick(wxCommandEvent& )
2518 {
2519     int index = m_lbStrings->GetSelection();
2520     if ( index > 0 )
2521     {
2522         ArraySwap(index-1,index);
2523         /*wxString old_str = m_array[index-1];
2524         wxString new_str = m_array[index];
2525         m_array[index-1] = new_str;
2526         m_array[index] = old_str;*/
2527         m_lbStrings->SetString ( index-1, ArrayGet(index-1) );
2528         m_lbStrings->SetString ( index, ArrayGet(index) );
2529         m_lbStrings->SetSelection ( index-1 );
2530         m_modified = true;
2531     }
2532 }
2533 
2534 // -----------------------------------------------------------------------
2535 
OnDownClick(wxCommandEvent &)2536 void wxArrayEditorDialog::OnDownClick(wxCommandEvent& )
2537 {
2538     int index = m_lbStrings->GetSelection();
2539     int lastStringIndex = ((int) m_lbStrings->GetCount()) - 1;
2540     if ( index >= 0 && index < lastStringIndex )
2541     {
2542         ArraySwap(index,index+1);
2543         /*wxString old_str = m_array[index+1];
2544         wxString new_str = m_array[index];
2545         m_array[index+1] = new_str;
2546         m_array[index] = old_str;*/
2547         m_lbStrings->SetString ( index+1, ArrayGet(index+1) );
2548         m_lbStrings->SetString ( index, ArrayGet(index) );
2549         m_lbStrings->SetSelection ( index+1 );
2550         m_modified = true;
2551     }
2552 }
2553 
2554 // -----------------------------------------------------------------------
2555 
OnUpdateClick(wxCommandEvent &)2556 void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent& )
2557 {
2558     int index = m_lbStrings->GetSelection();
2559     if ( index >= 0 )
2560     {
2561         wxString str = m_edValue->GetValue();
2562         if ( ArraySet(index,str) )
2563         {
2564             m_lbStrings->SetString ( index, str );
2565             //m_array[index] = str;
2566             m_modified = true;
2567         }
2568     }
2569 }
2570 
2571 // -----------------------------------------------------------------------
2572 
OnListBoxClick(wxCommandEvent &)2573 void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent& )
2574 {
2575     int index = m_lbStrings->GetSelection();
2576     if ( index >= 0 )
2577     {
2578         m_edValue->SetValue( m_lbStrings->GetString(index) );
2579     }
2580 }
2581 
2582 // -----------------------------------------------------------------------
2583 // wxPGArrayStringEditorDialog
2584 // -----------------------------------------------------------------------
2585 
IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog,wxArrayEditorDialog)2586 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
2587 
2588 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
2589     EVT_BUTTON(28, wxPGArrayStringEditorDialog::OnCustomEditClick)
2590 END_EVENT_TABLE()
2591 
2592 // -----------------------------------------------------------------------
2593 
2594 wxString wxPGArrayStringEditorDialog::ArrayGet( size_t index )
2595 {
2596     return m_array[index];
2597 }
2598 
ArrayGetCount()2599 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2600 {
2601     return m_array.GetCount();
2602 }
2603 
ArrayInsert(const wxString & str,int index)2604 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString& str, int index )
2605 {
2606     if (index<0)
2607         m_array.Add(str);
2608     else
2609         m_array.Insert(str,index);
2610     return true;
2611 }
2612 
ArraySet(size_t index,const wxString & str)2613 bool wxPGArrayStringEditorDialog::ArraySet( size_t index, const wxString& str )
2614 {
2615     m_array[index] = str;
2616     return true;
2617 }
2618 
ArrayRemoveAt(int index)2619 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index )
2620 {
2621     m_array.RemoveAt(index);
2622 }
2623 
ArraySwap(size_t first,size_t second)2624 void wxPGArrayStringEditorDialog::ArraySwap( size_t first, size_t second )
2625 {
2626     wxString old_str = m_array[first];
2627     wxString new_str = m_array[second];
2628     m_array[first] = new_str;
2629     m_array[second] = old_str;
2630 }
2631 
wxPGArrayStringEditorDialog()2632 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2633     : wxArrayEditorDialog()
2634 {
2635     Init();
2636 }
2637 
Init()2638 void wxPGArrayStringEditorDialog::Init()
2639 {
2640     m_pCallingClass = (wxArrayStringProperty*) NULL;
2641 }
2642 
OnCustomEditClick(wxCommandEvent &)2643 void wxPGArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent& )
2644 {
2645     wxASSERT( m_pCallingClass );
2646     wxString str = m_edValue->GetValue();
2647     if ( m_pCallingClass->OnCustomStringEdit(m_parent,str) )
2648     {
2649         //m_edValue->SetValue ( str );
2650         m_lbStrings->Append ( str );
2651         m_array.Add ( str );
2652         m_modified = true;
2653     }
2654 }
2655 
2656 // -----------------------------------------------------------------------
2657 // wxArrayStringProperty
2658 // -----------------------------------------------------------------------
2659 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty,wxPGProperty,wxArrayString,const wxArrayString &,TextCtrlAndButton)2660 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty,  // Property name
2661                                wxPGProperty,  // Property we inherit from
2662                                wxArrayString,  // Value type name
2663                                const wxArrayString&,  // Value type, as given in constructor
2664                                TextCtrlAndButton)  // Initial editor
2665 
2666 wxArrayStringProperty::wxArrayStringProperty( const wxString& label,
2667                                                         const wxString& name,
2668                                                         const wxArrayString& array )
2669     : wxPGProperty(label,name)
2670 {
2671     SetValue( array );
2672 }
2673 
~wxArrayStringProperty()2674 wxArrayStringProperty::~wxArrayStringProperty() { }
2675 
OnSetValue()2676 void wxArrayStringProperty::OnSetValue()
2677 {
2678     GenerateValueAsString();
2679 }
2680 
GetValueAsString(int WXUNUSED (argFlags)) const2681 wxString wxArrayStringProperty::GetValueAsString( int WXUNUSED(argFlags) ) const
2682 {
2683     return m_display;
2684 }
2685 
2686 // Converts wxArrayString to a string separated by delimeters and spaces.
2687 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2688 // conversion.
ArrayStringToString(wxString & dst,const wxArrayString & src,wxChar preDelim,wxChar postDelim,int flags)2689 void wxPropertyGrid::ArrayStringToString( wxString& dst, const wxArrayString& src,
2690                                           wxChar preDelim, wxChar postDelim,
2691                                           int flags )
2692 {
2693     wxString pdr;
2694 
2695     unsigned int i;
2696     unsigned int itemCount = src.GetCount();
2697 
2698     wxChar preas[2];
2699 
2700     dst.Empty();
2701 
2702     if ( !preDelim )
2703         preas[0] = 0;
2704     else if ( (flags & 1) )
2705     {
2706         preas[0] = preDelim;
2707         preas[1] = 0;
2708         pdr = wxT("\\");
2709         pdr += preDelim;
2710     }
2711 
2712     if ( itemCount )
2713         dst.append( preas );
2714 
2715     wxASSERT( postDelim );
2716     wxString postDelimStr(postDelim);
2717     //wxString preDelimStr(preDelim);
2718 
2719     for ( i = 0; i < itemCount; i++ )
2720     {
2721         wxString str( src.Item(i) );
2722 
2723         // Do some character conversion.
2724         // Convertes \ to \\ and <preDelim> to \<preDelim>
2725         // Useful when preDelim and postDelim are "\"".
2726         if ( flags & 1 )
2727         {
2728             str.Replace( wxT("\\"), wxT("\\\\"), true );
2729             if ( pdr.length() )
2730                 str.Replace( preas, pdr, true );
2731         }
2732 
2733         dst.append( str );
2734 
2735         if ( i < (itemCount-1) )
2736         {
2737             dst.append( postDelimStr );
2738             dst.append( wxT(" ") );
2739             dst.append( preas );
2740         }
2741         else if ( preDelim )
2742             dst.append( postDelimStr );
2743     }
2744 }
2745 
2746 #define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
2747     wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxT('"'),wxT('"'),1);
2748 
GenerateValueAsString()2749 void wxArrayStringProperty::GenerateValueAsString()
2750 {
2751     wxArrayString arr = m_value.GetArrayString();
2752     ARRSTRPROP_ARRAY_TO_STRING(m_display, arr)
2753 }
2754 
2755 // Default implementation doesn't do anything.
OnCustomStringEdit(wxWindow *,wxString &)2756 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow*, wxString& )
2757 {
2758     return false;
2759 }
2760 
CreateEditorDialog()2761 wxArrayEditorDialog* wxArrayStringProperty::CreateEditorDialog()
2762 {
2763     return new wxPGArrayStringEditorDialog();
2764 }
2765 
OnButtonClick(wxPropertyGrid * propGrid,wxWindow * WXUNUSED (primaryCtrl),const wxChar * cbt)2766 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid* propGrid,
2767                                            wxWindow* WXUNUSED(primaryCtrl),
2768                                            const wxChar* cbt )
2769 {
2770     // Update the value
2771     PrepareValueForDialogEditing(propGrid);
2772 
2773     if ( !propGrid->EditorValidate() )
2774         return false;
2775 
2776     // Create editor dialog.
2777     wxArrayEditorDialog* dlg = CreateEditorDialog();
2778 #if wxUSE_VALIDATORS
2779     wxValidator* validator = GetValidator();
2780     wxPGInDialogValidator dialogValidator;
2781 #endif
2782 
2783     wxPGArrayStringEditorDialog* strEdDlg = wxDynamicCast(dlg, wxPGArrayStringEditorDialog);
2784 
2785     if ( strEdDlg )
2786         strEdDlg->SetCustomButton(cbt, this);
2787 
2788     dlg->SetDialogValue( wxVariant(m_value) );
2789     dlg->Create(propGrid, wxEmptyString, m_label);
2790 
2791 #if !wxPG_SMALL_SCREEN
2792     dlg->Move( propGrid->GetGoodEditorDialogPosition(this,dlg->GetSize()) );
2793 #endif
2794 
2795     bool retVal;
2796 
2797     for (;;)
2798     {
2799         retVal = false;
2800 
2801         int res = dlg->ShowModal();
2802 
2803         if ( res == wxID_OK && dlg->IsModified() )
2804         {
2805             wxVariant value = dlg->GetDialogValue();
2806             if ( !value.IsNull() )
2807             {
2808                 wxArrayString actualValue = value.GetArrayString();
2809                 wxString tempStr;
2810                 ARRSTRPROP_ARRAY_TO_STRING(tempStr, actualValue)
2811             #if wxUSE_VALIDATORS
2812                 if ( dialogValidator.DoValidate( propGrid, validator, tempStr ) )
2813             #endif
2814                 {
2815                     SetValueInEvent( actualValue );
2816                     retVal = true;
2817                     break;
2818                 }
2819             }
2820             else
2821                 break;
2822         }
2823         else
2824             break;
2825     }
2826 
2827     delete dlg;
2828 
2829     return retVal;
2830 }
2831 
OnEvent(wxPropertyGrid * propGrid,wxWindow * primary,wxEvent & event)2832 bool wxArrayStringProperty::OnEvent( wxPropertyGrid* propGrid,
2833                                      wxWindow* primary,
2834                                      wxEvent& event )
2835 {
2836     if ( propGrid->IsMainButtonEvent(event) )
2837         return OnButtonClick(propGrid,primary,(const wxChar*) NULL);
2838     return false;
2839 }
2840 
StringToValue(wxVariant & variant,const wxString & text,int) const2841 bool wxArrayStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
2842 {
2843     wxArrayString arr;
2844 
2845     WX_PG_TOKENIZER2_BEGIN(text,wxT('"'))
2846 
2847         // Need to replace backslashes with empty characters
2848         // (opposite what is done in GenerateValueString).
2849         token.Replace ( wxT("\\\\"), wxT("\\"), true );
2850 
2851         arr.Add( token );
2852 
2853     WX_PG_TOKENIZER2_END()
2854 
2855     variant = arr;
2856 
2857     return true;
2858 }
2859 
2860 // -----------------------------------------------------------------------
2861 // wxCustomProperty
2862 // -----------------------------------------------------------------------
2863 
IMPLEMENT_DYNAMIC_CLASS(wxCustomProperty,wxPGProperty) const2864 IMPLEMENT_DYNAMIC_CLASS(wxCustomProperty, wxPGProperty)
2865 
2866 const wxPGEditor* wxCustomProperty::DoGetEditorClass() const
2867 {
2868     return wxPG_EDITOR(TextCtrl);
2869 }
2870 
wxCustomProperty(const wxString & label,const wxString & name)2871 wxCustomProperty::wxCustomProperty( const wxString& label,
2872                                     const wxString& name )
2873     : wxPGProperty(label,name)
2874 {
2875 #ifdef wxPG_COMPATIBILITY_1_0_0
2876     m_callback = (wxPropertyGridCallback) NULL;
2877 #endif
2878     m_paintCallback = (wxPGPaintCallback) NULL;
2879     m_value = wxPGVariant_EmptyString;  // Do this to avoid having 'unspecified' value
2880 }
2881 
~wxCustomProperty()2882 wxCustomProperty::~wxCustomProperty()
2883 {
2884 }
2885 
StringToValue(wxVariant & variant,const wxString & text,int WXUNUSED (argFlags)) const2886 bool wxCustomProperty::StringToValue( wxVariant& variant, const wxString& text, int WXUNUSED(argFlags) ) const
2887 {
2888     if ( text != m_value.GetString() )
2889     {
2890         variant = text;
2891         return true;
2892     }
2893     return false;
2894 }
2895 
GetValueAsString(int) const2896 wxString wxCustomProperty::GetValueAsString( int /*argFlags*/ ) const
2897 {
2898     return m_value;
2899 }
2900 
2901 // Need to do some extra event handling.
2902 #ifdef wxPG_COMPATIBILITY_1_0_0
OnEvent(wxPropertyGrid * propGrid,wxWindow * primary,wxEvent & event)2903 bool wxCustomProperty::OnEvent( wxPropertyGrid* propGrid, wxWindow* primary, wxEvent& event )
2904 {
2905     if ( propGrid->IsMainButtonEvent(event) )
2906     {
2907         if ( m_callback )
2908             return m_callback(propGrid,this,primary,0);
2909     }
2910     return false;
2911 }
2912 
2913 #endif
2914 
OnMeasureImage(int item) const2915 wxSize wxCustomProperty::OnMeasureImage( int item ) const
2916 {
2917     if ( m_paintCallback )
2918         return wxSize(-wxPG_CUSTOM_IMAGE_WIDTH,-wxPG_CUSTOM_IMAGE_WIDTH);
2919 
2920     return wxPGProperty::OnMeasureImage(item);
2921 }
2922 
OnCustomPaint(wxDC & dc,const wxRect & rect,wxPGPaintData & paintData)2923 void wxCustomProperty::OnCustomPaint( wxDC& dc,
2924                                            const wxRect& rect,
2925                                            wxPGPaintData& paintData )
2926 {
2927     if ( m_paintCallback )
2928         m_paintCallback(this,dc,rect,paintData);
2929     else
2930         wxPGProperty::OnCustomPaint(dc,rect,paintData);
2931 }
2932 
IntToValue(wxVariant & variant,int number,int) const2933 bool wxCustomProperty::IntToValue( wxVariant& variant, int number, int ) const
2934 {
2935     int index = m_choices.Index(number);
2936     if ( index == -1 )
2937         index = number;
2938 
2939     const wxString& sAtIndex = m_choices.GetLabel(index);
2940     if ( sAtIndex != m_value.GetString() )
2941     {
2942         variant = sAtIndex;
2943         return true;
2944     }
2945 
2946     return false;
2947 }
2948 
GetChoiceInfo(wxPGChoiceInfo * choiceinfo)2949 int wxCustomProperty::GetChoiceInfo( wxPGChoiceInfo* choiceinfo )
2950 {
2951     if ( choiceinfo )
2952         choiceinfo->m_choices = &m_choices;
2953 
2954     if ( !m_choices.IsOk() )
2955         return -1;
2956 
2957     return m_choices.Index(m_value.GetString());
2958 }
2959 
DoSetAttribute(const wxString & name,wxVariant & value)2960 bool wxCustomProperty::DoSetAttribute( const wxString& name, wxVariant& value )
2961 {
2962 #ifdef wxPG_COMPATIBILITY_1_0_0
2963     wxPropertyGrid* grid = GetGrid();
2964     if ( name == wxPG_CUSTOM_EDITOR )
2965     {
2966         if ( grid )
2967             grid->SetPropertyEditor( this, (wxPGEditor*) value.GetVoidPtr() );
2968         else
2969             SetEditor( (wxPGEditor*) value.GetVoidPtr() );
2970         return true;
2971     }
2972     else if ( name == wxPG_CUSTOM_IMAGE )
2973     {
2974         wxBitmap* bmp = (wxBitmap*) value.GetWxObjectPtr();
2975         if ( grid )
2976             grid->SetPropertyImage(this,*bmp);
2977         else
2978             SetValueImage(*bmp);
2979         return true;
2980     }
2981     else if ( name == wxPG_CUSTOM_CALLBACK )
2982     {
2983         m_callback = (wxPropertyGridCallback) value.GetVoidPtr();
2984         return true;
2985     }
2986     else
2987 #endif
2988     if ( name == wxPG_CUSTOM_PAINT_CALLBACK )
2989     {
2990         void* voidValue = value.GetVoidPtr();
2991         m_paintCallback = (wxPGPaintCallback) voidValue;
2992         if ( voidValue )
2993             m_flags |= wxPG_PROP_CUSTOMIMAGE;
2994         else if ( !GetValueImage() )
2995             m_flags &= ~(wxPG_PROP_CUSTOMIMAGE);
2996         return true;
2997     }
2998     else
2999     if ( name == wxPG_CUSTOM_PRIVATE_CHILDREN )
3000     {
3001         if ( wxPGVariantToInt(value) )
3002         {
3003             SetFlag( wxPG_PROP_AGGREGATE );
3004         }
3005         else
3006         {
3007             ClearFlag( wxPG_PROP_AGGREGATE );
3008         }
3009         return true;
3010     }
3011     return false;
3012 }
3013 
3014 // -----------------------------------------------------------------------
3015 
3016 #if wxUSE_VALIDATORS
DoValidate(wxPropertyGrid * propGrid,wxValidator * validator,const wxString & value)3017 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* propGrid,
3018                                         wxValidator* validator,
3019                                         const wxString& value )
3020 {
3021     if ( !validator )
3022         return true;
3023 
3024     wxTextCtrl* tc = m_textCtrl;
3025 
3026     if ( !tc )
3027     {
3028         {
3029             tc = new wxTextCtrl( propGrid, wxPG_SUBID_TEMP1, wxEmptyString,
3030                                  wxPoint(30000,30000));
3031             tc->Hide();
3032         }
3033 
3034         m_textCtrl = tc;
3035     }
3036 
3037     tc->SetValue(value);
3038 
3039     validator->SetWindow(tc);
3040     bool res = validator->Validate(propGrid);
3041 
3042     return res;
3043 }
3044 #else
DoValidate(wxPropertyGrid * WXUNUSED (propGrid),wxValidator * WXUNUSED (validator),const wxString & WXUNUSED (value))3045 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid* WXUNUSED(propGrid),
3046                                         wxValidator* WXUNUSED(validator),
3047                                         const wxString& WXUNUSED(value) )
3048 {
3049     return true;
3050 }
3051 #endif
3052 
3053 // -----------------------------------------------------------------------
3054 
3055