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