1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/props.cpp
3 // Purpose: Basic Property Classes
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
23 #include "wx/object.h"
25 #include "wx/string.h"
28 #include "wx/window.h"
31 #include "wx/dcclient.h"
32 #include "wx/dcmemory.h"
33 #include "wx/button.h"
34 #include "wx/bmpbuttn.h"
37 #include "wx/cursor.h"
38 #include "wx/dialog.h"
39 #include "wx/settings.h"
40 #include "wx/msgdlg.h"
41 #include "wx/choice.h"
42 #include "wx/stattext.h"
43 #include "wx/scrolwin.h"
44 #include "wx/dirdlg.h"
45 #include "wx/combobox.h"
46 #include "wx/layout.h"
48 #include "wx/textdlg.h"
49 #include "wx/filedlg.h"
53 #include "wx/filename.h"
55 #include "wx/propgrid/propgrid.h"
57 #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
60 // -----------------------------------------------------------------------
62 // -----------------------------------------------------------------------
64 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty
,wxPGProperty
,
65 wxString
,const wxString
&,TextCtrl
)
67 wxStringProperty::wxStringProperty( const wxString
& label
,
69 const wxString
& value
)
70 : wxPGProperty(label
,name
)
75 void wxStringProperty::OnSetValue()
77 if ( !m_value
.IsNull() && m_value
.GetString() == wxS("<composed>") )
78 SetFlag(wxPG_PROP_COMPOSED_VALUE
);
80 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
83 DoGenerateComposedValue(s
);
88 wxStringProperty::~wxStringProperty() { }
90 wxString
wxStringProperty::ValueToString( wxVariant
& value
,
93 wxString s
= value
.GetString();
95 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
97 // Value stored in m_value is non-editable, non-full value
98 if ( (argFlags
& wxPG_FULL_VALUE
) || (argFlags
& wxPG_EDITABLE_VALUE
) )
100 // Calling this under incorrect conditions will fail
101 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
102 "Sorry, currently default wxPGProperty::ValueToString() "
103 "implementation only works if value is m_value." );
105 DoGenerateComposedValue(s
, argFlags
);
111 // If string is password and value is for visual purposes,
112 // then return asterisks instead the actual string.
113 if ( (m_flags
& wxPG_PROP_PASSWORD
) && !(argFlags
& (wxPG_FULL_VALUE
|wxPG_EDITABLE_VALUE
)) )
114 return wxString(wxChar('*'), s
.Length());
119 bool wxStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
121 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
122 return wxPGProperty::StringToValue(variant
, text
, argFlags
);
124 if ( variant
!= text
)
133 bool wxStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
135 if ( name
== wxPG_STRING_PASSWORD
)
137 m_flags
&= ~(wxPG_PROP_PASSWORD
);
138 if ( value
.GetLong() ) m_flags
|= wxPG_PROP_PASSWORD
;
145 // -----------------------------------------------------------------------
146 // wxNumericPropertyValidator
147 // -----------------------------------------------------------------------
151 wxNumericPropertyValidator::
152 wxNumericPropertyValidator( NumericType numericType
, int base
)
153 : wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST
)
171 arr
.Add(wxS("a")); arr
.Add(wxS("A"));
172 arr
.Add(wxS("b")); arr
.Add(wxS("B"));
173 arr
.Add(wxS("c")); arr
.Add(wxS("C"));
174 arr
.Add(wxS("d")); arr
.Add(wxS("D"));
175 arr
.Add(wxS("e")); arr
.Add(wxS("E"));
176 arr
.Add(wxS("f")); arr
.Add(wxS("F"));
180 if ( numericType
== Signed
)
185 else if ( numericType
== Float
)
191 // Use locale-specific decimal point
192 arr
.Add(wxString::Format("%g", 1.1)[1]);
198 bool wxNumericPropertyValidator::Validate(wxWindow
* parent
)
200 if ( !wxTextValidator::Validate(parent
) )
203 wxWindow
* wnd
= GetWindow();
204 if ( !wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
207 // Do not allow zero-length string
208 wxTextCtrl
* tc
= static_cast<wxTextCtrl
*>(wnd
);
209 wxString text
= tc
->GetValue();
211 if ( !text
.length() )
217 #endif // wxUSE_VALIDATORS
219 // -----------------------------------------------------------------------
221 // -----------------------------------------------------------------------
223 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
226 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
227 long value
) : wxPGProperty(label
,name
)
232 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
233 const wxLongLong
& value
) : wxPGProperty(label
,name
)
235 SetValue(WXVARIANT(value
));
238 wxIntProperty::~wxIntProperty() { }
240 wxString
wxIntProperty::ValueToString( wxVariant
& value
,
241 int WXUNUSED(argFlags
) ) const
243 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
245 return wxString::Format(wxS("%li"),value
.GetLong());
247 else if ( value
.GetType() == wxPG_VARIANT_TYPE_LONGLONG
)
249 wxLongLong ll
= value
.GetLongLong();
250 return ll
.ToString();
253 return wxEmptyString
;
256 bool wxIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
261 if ( text
.length() == 0 )
267 // We know it is a number, but let's still check
269 if ( text
.IsNumber() )
271 // Remove leading zeroes, so that the number is not interpreted as octal
272 wxString::const_iterator i
= text
.begin();
273 wxString::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
275 int firstNonZeroPos
= 0;
277 for ( ; i
!= iMax
; ++i
)
280 if ( c
!= wxS('0') && c
!= wxS(' ') )
285 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
287 wxString variantType
= variant
.GetType();
288 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
290 wxLongLong_t value64
= 0;
292 if ( useText
.ToLongLong(&value64
, 10) &&
293 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
296 bool doChangeValue
= isPrevLong
;
298 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_LONGLONG
)
300 wxLongLong oldValue
= variant
.GetLongLong();
301 if ( oldValue
.GetValue() != value64
)
302 doChangeValue
= true;
307 wxLongLong
ll(value64
);
313 if ( useText
.ToLong( &value32
, 0 ) )
315 if ( !isPrevLong
|| variant
!= value32
)
322 else if ( argFlags
& wxPG_REPORT_ERROR
)
328 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
330 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
!= (long)value
)
332 variant
= (long)value
;
339 // Common validation code to be called in ValidateValue()
342 // Note that 'value' is reference on purpose, so we can write
343 // back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE.
346 bool NumericValidation( const wxPGProperty
* property
,
348 wxPGValidationInfo
* pValidationInfo
,
350 const wxString
& strFmt
)
352 T min
= (T
) wxINT64_MIN
;
353 T max
= (T
) wxINT64_MAX
;
358 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
359 if ( !variant
.IsNull() )
361 variant
.Convert(&min
);
365 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
366 if ( !variant
.IsNull() )
368 variant
.Convert(&max
);
376 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
379 wxString smin
= wxString::Format(strFmt
, min
);
380 wxString smax
= wxString::Format(strFmt
, max
);
382 msg
= wxString::Format(
383 _("Value must be %s or higher."),
386 msg
= wxString::Format(
387 _("Value must be between %s and %s."),
388 smin
.c_str(), smax
.c_str());
389 pValidationInfo
->SetFailureMessage(msg
);
391 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
394 value
= max
- (min
- value
);
403 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
406 wxString smin
= wxString::Format(strFmt
, min
);
407 wxString smax
= wxString::Format(strFmt
, max
);
409 msg
= wxString::Format(
410 _("Value must be %s or less."),
413 msg
= wxString::Format(
414 _("Value must be between %s and %s."),
415 smin
.c_str(), smax
.c_str());
416 pValidationInfo
->SetFailureMessage(msg
);
418 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
421 value
= min
+ (value
- max
);
428 bool wxIntProperty::DoValidation( const wxPGProperty
* property
,
430 wxPGValidationInfo
* pValidationInfo
,
433 return NumericValidation
<wxLongLong_t
>(property
,
440 bool wxIntProperty::ValidateValue( wxVariant
& value
,
441 wxPGValidationInfo
& validationInfo
) const
443 wxLongLong_t ll
= value
.GetLongLong().GetValue();
444 return DoValidation(this, ll
, &validationInfo
,
445 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
448 wxValidator
* wxIntProperty::GetClassValidator()
451 WX_PG_DOGETVALIDATOR_ENTRY()
453 wxValidator
* validator
= new wxNumericPropertyValidator(
454 wxNumericPropertyValidator::Signed
);
456 WX_PG_DOGETVALIDATOR_EXIT(validator
)
462 wxValidator
* wxIntProperty::DoGetValidator() const
464 return GetClassValidator();
467 // -----------------------------------------------------------------------
469 // -----------------------------------------------------------------------
472 #define wxPG_UINT_TEMPLATE_MAX 8
474 static const wxChar
* const gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
475 wxT("%x"),wxT("0x%x"),wxT("$%x"),
476 wxT("%X"),wxT("0x%X"),wxT("$%X"),
480 static const char* const gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
481 "%" wxLongLongFmtSpec
"x",
482 "0x%" wxLongLongFmtSpec
"x",
483 "$%" wxLongLongFmtSpec
"x",
484 "%" wxLongLongFmtSpec
"X",
485 "0x%" wxLongLongFmtSpec
"X",
486 "$%" wxLongLongFmtSpec
"X",
487 "%" wxLongLongFmtSpec
"u",
488 "%" wxLongLongFmtSpec
"o"
491 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
492 long,unsigned long,TextCtrl
)
494 void wxUIntProperty::Init()
496 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
498 m_prefix
= wxPG_PREFIX_NONE
;
501 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
502 unsigned long value
) : wxPGProperty(label
,name
)
505 SetValue((long)value
);
508 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
509 const wxULongLong
& value
) : wxPGProperty(label
,name
)
512 SetValue(WXVARIANT(value
));
515 wxUIntProperty::~wxUIntProperty() { }
517 wxString
wxUIntProperty::ValueToString( wxVariant
& value
,
518 int WXUNUSED(argFlags
) ) const
520 size_t index
= m_base
+ m_prefix
;
521 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
522 index
= wxPG_BASE_DEC
;
524 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
526 return wxString::Format(gs_uintTemplates32
[index
],
527 (unsigned long)value
.GetLong());
530 wxULongLong ull
= value
.GetULongLong();
532 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
535 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
537 wxString variantType
= variant
.GetType();
538 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
540 if ( text
.length() == 0 )
547 if ( text
[0] == wxS('$') )
550 wxULongLong_t value64
= 0;
551 wxString s
= text
.substr(start
, text
.length() - start
);
553 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
555 if ( value64
>= LONG_MAX
)
557 bool doChangeValue
= isPrevLong
;
559 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_ULONGLONG
)
561 wxULongLong oldValue
= variant
.GetULongLong();
562 if ( oldValue
.GetValue() != value64
)
563 doChangeValue
= true;
568 variant
= wxULongLong(value64
);
574 unsigned long value32
= wxLongLong(value64
).GetLo();
575 if ( !isPrevLong
|| m_value
!= (long)value32
)
577 variant
= (long)value32
;
586 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
588 if ( variant
!= (long)number
)
590 variant
= (long)number
;
596 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
598 wxULongLong_t uul
= value
.GetULongLong().GetValue();
600 NumericValidation
<wxULongLong_t
>(this,
603 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
,
607 wxValidator
* wxUIntProperty::DoGetValidator() const
610 WX_PG_DOGETVALIDATOR_ENTRY()
612 wxValidator
* validator
= new wxNumericPropertyValidator(
613 wxNumericPropertyValidator::Unsigned
,
616 WX_PG_DOGETVALIDATOR_EXIT(validator
)
622 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
624 if ( name
== wxPG_UINT_BASE
)
626 int val
= value
.GetLong();
628 m_realBase
= (wxByte
) val
;
629 if ( m_realBase
> 16 )
633 // Translate logical base to a template array index
635 if ( val
== wxPG_BASE_HEX
)
637 else if ( val
== wxPG_BASE_DEC
)
639 else if ( val
== wxPG_BASE_HEXL
)
643 else if ( name
== wxPG_UINT_PREFIX
)
645 m_prefix
= (wxByte
) value
.GetLong();
651 // -----------------------------------------------------------------------
653 // -----------------------------------------------------------------------
655 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
656 double,double,TextCtrl
)
658 wxFloatProperty::wxFloatProperty( const wxString
& label
,
659 const wxString
& name
,
661 : wxPGProperty(label
,name
)
667 wxFloatProperty::~wxFloatProperty() { }
669 // This helper method provides standard way for floating point-using
670 // properties to convert values to string.
671 const wxString
& wxPropertyGrid::DoubleToString(wxString
& target
,
675 wxString
* precTemplate
)
677 if ( precision
>= 0 )
681 precTemplate
= &text1
;
683 if ( !precTemplate
->length() )
685 *precTemplate
= wxS("%.");
686 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
687 *precTemplate
<< wxS('f');
690 target
.Printf( precTemplate
->c_str(), value
);
694 target
.Printf( wxS("%f"), value
);
697 if ( removeZeroes
&& precision
!= 0 && target
.length() )
699 // Remove excess zeroes (do not remove this code just yet,
700 // since sprintf can't do the same consistently across platforms).
701 wxString::const_iterator i
= target
.end() - 1;
702 size_t new_len
= target
.length() - 1;
704 for ( ; i
!= target
.begin(); --i
)
706 if ( *i
!= wxS('0') )
711 wxChar cur_char
= *i
;
712 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
715 if ( new_len
!= target
.length() )
716 target
.resize(new_len
);
719 // Remove sign from zero
720 if ( target
.length() >= 2 && target
[0] == wxS('-') )
723 wxString::const_iterator i
= target
.begin() + 1;
725 for ( ; i
!= target
.end(); i
++ )
727 if ( *i
!= wxS('0') && *i
!= wxS('.') && *i
!= wxS(',') )
735 target
.erase(target
.begin());
741 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
745 if ( !value
.IsNull() )
747 wxPropertyGrid::DoubleToString(text
,
750 !(argFlags
& wxPG_FULL_VALUE
),
756 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
761 if ( text
.length() == 0 )
767 bool res
= text
.ToDouble(&value
);
770 if ( variant
!= value
)
776 else if ( argFlags
& wxPG_REPORT_ERROR
)
782 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
784 wxPGValidationInfo
* pValidationInfo
,
787 return NumericValidation
<double>(property
,
795 wxFloatProperty::ValidateValue( wxVariant
& value
,
796 wxPGValidationInfo
& validationInfo
) const
798 double fpv
= value
.GetDouble();
799 return DoValidation(this, fpv
, &validationInfo
,
800 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
803 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
805 if ( name
== wxPG_FLOAT_PRECISION
)
807 m_precision
= value
.GetLong();
814 wxFloatProperty::GetClassValidator()
817 WX_PG_DOGETVALIDATOR_ENTRY()
819 wxValidator
* validator
= new wxNumericPropertyValidator(
820 wxNumericPropertyValidator::Float
);
822 WX_PG_DOGETVALIDATOR_EXIT(validator
)
828 wxValidator
* wxFloatProperty::DoGetValidator() const
830 return GetClassValidator();
833 // -----------------------------------------------------------------------
835 // -----------------------------------------------------------------------
837 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
838 // there is a custom GetEditorClass.
840 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
842 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
844 // Select correct editor control.
845 #if wxPG_INCLUDE_CHECKBOX
846 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
847 return wxPGEditor_Choice
;
848 return wxPGEditor_CheckBox
;
850 return wxPGEditor_Choice
;
854 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
855 wxPGProperty(label
,name
)
857 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
859 SetValue(wxPGVariant_Bool(value
));
861 m_flags
|= wxPG_PROP_USE_DCC
;
864 wxBoolProperty::~wxBoolProperty() { }
866 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
869 bool boolValue
= value
.GetBool();
871 // As a fragment of composite string value,
872 // make it a little more readable.
873 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
881 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
882 return wxEmptyString
;
885 if ( wxPGGlobalVars
->m_autoGetTranslation
)
886 notFmt
= _("Not %s");
888 notFmt
= wxS("Not %s");
890 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
894 if ( !(argFlags
& wxPG_FULL_VALUE
) )
896 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
901 if ( boolValue
) text
= wxS("true");
902 else text
= wxS("false");
907 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
909 bool boolValue
= false;
910 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
911 text
.CmpNoCase(wxS("true")) == 0 ||
912 text
.CmpNoCase(m_label
) == 0 )
915 if ( text
.length() == 0 )
921 if ( variant
!= boolValue
)
923 variant
= wxPGVariant_Bool(boolValue
);
929 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
931 bool boolValue
= value
? true : false;
933 if ( variant
!= boolValue
)
935 variant
= wxPGVariant_Bool(boolValue
);
941 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
943 #if wxPG_INCLUDE_CHECKBOX
944 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
946 if ( value
.GetLong() )
947 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
949 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
953 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
955 if ( value
.GetLong() )
956 m_flags
|= wxPG_PROP_USE_DCC
;
958 m_flags
&= ~(wxPG_PROP_USE_DCC
);
964 // -----------------------------------------------------------------------
966 // -----------------------------------------------------------------------
968 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
970 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
972 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
973 const long* values
, int value
) : wxPGProperty(label
,name
)
979 m_choices
.Add(labels
,values
);
981 if ( GetItemCount() )
982 SetValue( (long)value
);
986 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
987 const long* values
, wxPGChoices
* choicesCache
, int value
)
988 : wxPGProperty(label
,name
)
992 wxASSERT( choicesCache
);
994 if ( choicesCache
->IsOk() )
996 m_choices
.Assign( *choicesCache
);
997 m_value
= wxPGVariant_Zero
;
1001 m_choices
.Add(labels
,values
);
1003 if ( GetItemCount() )
1004 SetValue( (long)value
);
1008 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1009 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1010 : wxPGProperty(label
,name
)
1014 if ( &labels
&& labels
.size() )
1016 m_choices
.Set(labels
, values
);
1018 if ( GetItemCount() )
1019 SetValue( (long)value
);
1023 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1024 wxPGChoices
& choices
, int value
)
1025 : wxPGProperty(label
,name
)
1027 m_choices
.Assign( choices
);
1029 if ( GetItemCount() )
1030 SetValue( (long)value
);
1033 int wxEnumProperty::GetIndexForValue( int value
) const
1035 if ( !m_choices
.IsOk() )
1038 int intVal
= m_choices
.Index(value
);
1045 wxEnumProperty::~wxEnumProperty ()
1049 int wxEnumProperty::ms_nextIndex
= -2;
1051 void wxEnumProperty::OnSetValue()
1053 wxString variantType
= m_value
.GetType();
1055 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
1057 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
1059 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
1061 ValueFromString_( m_value
, m_value
.GetString(), 0 );
1068 if ( ms_nextIndex
!= -2 )
1070 m_index
= ms_nextIndex
;
1075 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
1077 // Make sure string value is in the list,
1078 // unless property has string as preferred value type
1079 // To reduce code size, use conversion here as well
1080 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
1081 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
1082 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
1087 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
1088 int WXUNUSED(argFlags
) ) const
1090 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
1091 return value
.GetString();
1093 int index
= m_choices
.Index(value
.GetLong());
1095 return wxEmptyString
;
1097 return m_choices
.GetLabel(index
);
1100 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1102 return ValueFromString_( variant
, text
, argFlags
);
1105 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
1107 return ValueFromInt_( variant
, intVal
, argFlags
);
1110 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
1115 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
1117 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
1118 if ( text
.CmpNoCase(entryLabel
) == 0 )
1121 useValue
= m_choices
.GetValue(i
);
1126 bool asText
= false;
1128 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
1130 // If text not any of the choices, store as text instead
1131 // (but only if we are wxEditEnumProperty)
1132 if ( useIndex
== -1 && isEdit
)
1137 int setAsNextIndex
= -2;
1141 setAsNextIndex
= -1;
1144 else if ( useIndex
!= GetIndex() )
1146 if ( useIndex
!= -1 )
1148 setAsNextIndex
= useIndex
;
1149 value
= (long)useValue
;
1153 setAsNextIndex
= -1;
1154 value
= wxPGVariant_MinusOne
;
1158 if ( setAsNextIndex
!= -2 )
1160 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1161 // validation purposes only, and index must not be changed
1162 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1163 ms_nextIndex
= setAsNextIndex
;
1165 if ( isEdit
|| setAsNextIndex
!= -1 )
1173 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1175 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1179 if ( argFlags
& wxPG_FULL_VALUE
)
1181 ms_nextIndex
= GetIndexForValue( intVal
);
1185 if ( intVal
!= GetIndex() )
1187 ms_nextIndex
= intVal
;
1191 if ( ms_nextIndex
!= -2 )
1193 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1194 intVal
= m_choices
.GetValue(intVal
);
1196 variant
= (long)intVal
;
1205 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1211 void wxEnumProperty::SetIndex( int index
)
1217 int wxEnumProperty::GetIndex() const
1219 if ( m_value
.IsNull() )
1222 if ( ms_nextIndex
!= -2 )
1223 return ms_nextIndex
;
1228 // -----------------------------------------------------------------------
1229 // wxEditEnumProperty
1230 // -----------------------------------------------------------------------
1232 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1234 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1236 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1237 const long* values
, const wxString
& value
)
1238 : wxEnumProperty(label
,name
,labels
,values
,0)
1243 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1244 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1245 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1250 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1251 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1252 : wxEnumProperty(label
,name
,labels
,values
,0)
1257 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1258 wxPGChoices
& choices
, const wxString
& value
)
1259 : wxEnumProperty(label
,name
,choices
,0)
1264 wxEditEnumProperty::~wxEditEnumProperty()
1268 // -----------------------------------------------------------------------
1270 // -----------------------------------------------------------------------
1272 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1274 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1276 void wxFlagsProperty::Init()
1278 long value
= m_value
;
1281 // Generate children
1285 unsigned int prevChildCount
= m_children
.size();
1288 if ( prevChildCount
)
1290 wxPropertyGridPageState
* state
= GetParentState();
1292 // State safety check (it may be NULL in immediate parent)
1297 wxPGProperty
* selected
= state
->GetSelection();
1300 if ( selected
->GetParent() == this )
1301 oldSel
= selected
->GetIndexInParent();
1302 else if ( selected
== this )
1306 state
->DoClearSelection();
1309 // Delete old children
1310 for ( i
=0; i
<prevChildCount
; i
++ )
1311 delete m_children
[i
];
1315 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1316 // to child bool property controls.
1317 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1318 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1321 if ( m_choices
.IsOk() )
1323 const wxPGChoices
& choices
= m_choices
;
1325 for ( i
=0; i
<GetItemCount(); i
++ )
1328 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1330 wxPGProperty
* boolProp
;
1331 wxString label
= GetLabel(i
);
1334 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1336 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1341 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1343 if ( attrUseCheckBox
)
1344 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1347 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1349 AddPrivateChild(boolProp
);
1352 m_oldChoicesData
= m_choices
.GetDataPtr();
1355 m_oldValue
= m_value
;
1357 if ( prevChildCount
)
1358 SubPropsChanged(oldSel
);
1361 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1362 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1364 m_oldChoicesData
= NULL
;
1368 m_choices
.Set(labels
,values
);
1370 wxASSERT( GetItemCount() );
1376 m_value
= wxPGVariant_Zero
;
1380 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1381 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1382 : wxPGProperty(label
,name
)
1384 m_oldChoicesData
= NULL
;
1386 if ( &labels
&& labels
.size() )
1388 m_choices
.Set(labels
,values
);
1390 wxASSERT( GetItemCount() );
1392 SetValue( (long)value
);
1396 m_value
= wxPGVariant_Zero
;
1400 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1401 wxPGChoices
& choices
, long value
)
1402 : wxPGProperty(label
,name
)
1404 m_oldChoicesData
= NULL
;
1406 if ( choices
.IsOk() )
1408 m_choices
.Assign(choices
);
1410 wxASSERT( GetItemCount() );
1416 m_value
= wxPGVariant_Zero
;
1420 wxFlagsProperty::~wxFlagsProperty()
1424 void wxFlagsProperty::OnSetValue()
1426 if ( !m_choices
.IsOk() || !GetItemCount() )
1428 m_value
= wxPGVariant_Zero
;
1432 long val
= m_value
.GetLong();
1436 // normalize the value (i.e. remove extra flags)
1438 const wxPGChoices
& choices
= m_choices
;
1439 for ( i
= 0; i
< GetItemCount(); i
++ )
1441 fullFlags
|= choices
.GetValue(i
);
1448 // Need to (re)init now?
1449 if ( GetChildCount() != GetItemCount() ||
1450 m_choices
.GetDataPtr() != m_oldChoicesData
)
1456 long newFlags
= m_value
;
1458 if ( newFlags
!= m_oldValue
)
1460 // Set child modified states
1462 const wxPGChoices
& choices
= m_choices
;
1463 for ( i
= 0; i
<GetItemCount(); i
++ )
1467 flag
= choices
.GetValue(i
);
1469 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1470 Item(i
)->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1473 m_oldValue
= newFlags
;
1477 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1478 int WXUNUSED(argFlags
) ) const
1482 if ( !m_choices
.IsOk() )
1487 const wxPGChoices
& choices
= m_choices
;
1489 for ( i
= 0; i
< GetItemCount(); i
++ )
1492 doAdd
= ( flags
& choices
.GetValue(i
) );
1496 text
+= choices
.GetLabel(i
);
1501 // remove last comma
1502 if ( text
.Len() > 1 )
1503 text
.Truncate ( text
.Len() - 2 );
1508 // Translate string into flag tokens
1509 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1511 if ( !m_choices
.IsOk() )
1516 // semicolons are no longer valid delimeters
1517 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1519 if ( token
.length() )
1521 // Determine which one it is
1522 long bit
= IdToBit( token
);
1535 WX_PG_TOKENIZER1_END()
1537 if ( variant
!= (long)newFlags
)
1539 variant
= (long)newFlags
;
1546 // Converts string id to a relevant bit.
1547 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1550 for ( i
= 0; i
< GetItemCount(); i
++ )
1552 if ( id
== GetLabel(i
) )
1554 return m_choices
.GetValue(i
);
1560 void wxFlagsProperty::RefreshChildren()
1562 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1564 int flags
= m_value
.GetLong();
1566 const wxPGChoices
& choices
= m_choices
;
1568 for ( i
= 0; i
< GetItemCount(); i
++ )
1572 flag
= choices
.GetValue(i
);
1574 long subVal
= flags
& flag
;
1575 wxPGProperty
* p
= Item(i
);
1577 if ( subVal
!= (m_oldValue
& flag
) )
1578 p
->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1580 p
->SetValue( subVal
?true:false );
1586 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1588 wxVariant
& childValue
) const
1590 long oldValue
= thisValue
.GetLong();
1591 long val
= childValue
.GetLong();
1592 unsigned long vi
= m_choices
.GetValue(childIndex
);
1595 return (long) (oldValue
| vi
);
1597 return (long) (oldValue
& ~(vi
));
1600 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1602 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1603 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1605 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1607 Item(i
)->SetAttribute(name
, value
);
1609 // Must return false so that the attribute is stored in
1610 // flag property's actual property storage
1616 // -----------------------------------------------------------------------
1618 // -----------------------------------------------------------------------
1620 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1622 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1623 : wxLongStringProperty(name
,label
,value
)
1625 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1628 wxDirProperty::~wxDirProperty() { }
1630 wxValidator
* wxDirProperty::DoGetValidator() const
1632 return wxFileProperty::GetClassValidator();
1635 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1637 // Update property value from editor, if necessary
1638 wxSize
dlg_sz(300,400);
1640 wxString
dlgMessage(m_dlgMessage
);
1641 if ( dlgMessage
.empty() )
1642 dlgMessage
= _("Choose a directory:");
1643 wxDirDialog
dlg( propGrid
,
1647 #if !wxPG_SMALL_SCREEN
1648 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1656 if ( dlg
.ShowModal() == wxID_OK
)
1658 value
= dlg
.GetPath();
1664 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1666 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1668 m_dlgMessage
= value
.GetString();
1674 // -----------------------------------------------------------------------
1675 // wxPGFileDialogAdapter
1676 // -----------------------------------------------------------------------
1678 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1680 wxFileProperty
* fileProp
= NULL
;
1684 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1686 fileProp
= ((wxFileProperty
*)property
);
1687 wxFileName filename
= fileProp
->GetValue().GetString();
1688 path
= filename
.GetPath();
1689 indFilter
= fileProp
->m_indFilter
;
1691 if ( !path
.length() && fileProp
->m_basePath
.length() )
1692 path
= fileProp
->m_basePath
;
1696 wxFileName
fn(property
->GetValue().GetString());
1697 path
= fn
.GetPath();
1700 wxFileDialog
dlg( propGrid
->GetPanel(),
1701 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1702 property
->GetAttribute(wxS("InitialPath"), path
),
1704 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1706 wxDefaultPosition
);
1708 if ( indFilter
>= 0 )
1709 dlg
.SetFilterIndex( indFilter
);
1711 if ( dlg
.ShowModal() == wxID_OK
)
1714 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1715 SetValue( dlg
.GetPath() );
1721 // -----------------------------------------------------------------------
1723 // -----------------------------------------------------------------------
1725 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1726 wxString
,const wxString
&,TextCtrlAndButton
)
1728 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1729 const wxString
& value
) : wxPGProperty(label
,name
)
1731 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1733 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1738 wxFileProperty::~wxFileProperty() {}
1740 wxValidator
* wxFileProperty::GetClassValidator()
1742 #if wxUSE_VALIDATORS
1743 WX_PG_DOGETVALIDATOR_ENTRY()
1745 // Atleast wxPython 2.6.2.1 required that the string argument is given
1747 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1749 wxArrayString exChars
;
1750 exChars
.Add(wxS("?"));
1751 exChars
.Add(wxS("*"));
1752 exChars
.Add(wxS("|"));
1753 exChars
.Add(wxS("<"));
1754 exChars
.Add(wxS(">"));
1755 exChars
.Add(wxS("\""));
1757 validator
->SetExcludes(exChars
);
1759 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1765 wxValidator
* wxFileProperty::DoGetValidator() const
1767 return GetClassValidator();
1770 void wxFileProperty::OnSetValue()
1772 const wxString
& fnstr
= m_value
.GetString();
1774 wxFileName filename
= fnstr
;
1776 if ( !filename
.HasName() )
1778 m_value
= wxPGVariant_EmptyString
;
1781 // Find index for extension.
1782 if ( m_indFilter
< 0 && fnstr
.length() )
1784 wxString ext
= filename
.GetExt();
1787 size_t len
= m_wildcard
.length();
1789 pos
= m_wildcard
.find(wxS("|"), pos
);
1790 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1792 size_t ext_begin
= pos
+ 3;
1794 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1795 if ( pos
== wxString::npos
)
1797 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1799 if ( found_ext
.length() > 0 )
1801 if ( found_ext
[0] == wxS('*') )
1803 m_indFilter
= curind
;
1806 if ( ext
.CmpNoCase(found_ext
) == 0 )
1808 m_indFilter
= curind
;
1814 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1821 wxFileName
wxFileProperty::GetFileName() const
1823 wxFileName filename
;
1825 if ( !m_value
.IsNull() )
1826 filename
= m_value
.GetString();
1831 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1832 int argFlags
) const
1834 wxFileName filename
= value
.GetString();
1836 if ( !filename
.HasName() )
1837 return wxEmptyString
;
1839 wxString fullName
= filename
.GetFullName();
1840 if ( !fullName
.length() )
1841 return wxEmptyString
;
1843 if ( argFlags
& wxPG_FULL_VALUE
)
1845 return filename
.GetFullPath();
1847 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1849 if ( m_basePath
.Length() )
1851 wxFileName
fn2(filename
);
1852 fn2
.MakeRelativeTo(m_basePath
);
1853 return fn2
.GetFullPath();
1855 return filename
.GetFullPath();
1858 return filename
.GetFullName();
1861 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1863 return new wxPGFileDialogAdapter();
1866 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1868 wxFileName filename
= variant
.GetString();
1870 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1872 if ( filename
!= text
)
1880 if ( filename
.GetFullName() != text
)
1882 wxFileName fn
= filename
;
1883 fn
.SetFullName(text
);
1884 variant
= fn
.GetFullPath();
1892 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1894 // Return false on some occasions to make sure those attribs will get
1895 // stored in m_attributes.
1896 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1898 if ( value
.GetLong() )
1899 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1901 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1904 else if ( name
== wxPG_FILE_WILDCARD
)
1906 m_wildcard
= value
.GetString();
1908 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1910 m_basePath
= value
.GetString();
1912 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1913 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1915 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1917 m_initialPath
= value
.GetString();
1920 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1922 m_dlgTitle
= value
.GetString();
1928 // -----------------------------------------------------------------------
1929 // wxPGLongStringDialogAdapter
1930 // -----------------------------------------------------------------------
1932 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1934 wxString val1
= property
->GetValueAsString(0);
1935 wxString val_orig
= val1
;
1938 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1939 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1941 value
= wxString(val1
);
1943 // Run editor dialog.
1944 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1946 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1947 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1951 if ( val1
!= val_orig
)
1960 // -----------------------------------------------------------------------
1961 // wxLongStringProperty
1962 // -----------------------------------------------------------------------
1964 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1965 wxString
,const wxString
&,TextCtrlAndButton
)
1967 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1968 const wxString
& value
) : wxPGProperty(label
,name
)
1973 wxLongStringProperty::~wxLongStringProperty() {}
1975 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1976 int WXUNUSED(argFlags
) ) const
1981 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1984 if ( propGrid
->IsMainButtonEvent(event
) )
1987 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1989 wxString val1
= useValue
.GetString();
1990 wxString val_orig
= val1
;
1993 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1994 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1996 value
= wxString(val1
);
1998 // Run editor dialog.
1999 if ( OnButtonClick(propGrid
,value
) )
2001 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
2002 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
2006 if ( val1
!= val_orig
)
2008 SetValueInEvent( val1
);
2016 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
2018 return DisplayEditorDialog(this, propGrid
, value
);
2021 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
2024 // launch editor dialog
2025 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
2026 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
2028 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
2030 // Multi-line text editor dialog.
2031 #if !wxPG_SMALL_SCREEN
2032 const int spacing
= 8;
2034 const int spacing
= 4;
2036 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2037 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2038 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
2039 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
2041 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
2042 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
2044 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2045 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
2046 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
2047 buttonSizer
->Realize();
2048 topsizer
->Add( buttonSizer
, 0,
2049 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
2052 dlg
->SetSizer( topsizer
);
2053 topsizer
->SetSizeHints( dlg
);
2055 #if !wxPG_SMALL_SCREEN
2056 dlg
->SetSize(400,300);
2058 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
2061 int res
= dlg
->ShowModal();
2063 if ( res
== wxID_OK
)
2065 value
= ed
->GetValue();
2073 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2075 if ( variant
!= text
)
2083 #if wxUSE_EDITABLELISTBOX
2085 // -----------------------------------------------------------------------
2086 // wxPGArrayEditorDialog
2087 // -----------------------------------------------------------------------
2089 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog
, wxDialog
)
2090 EVT_IDLE(wxPGArrayEditorDialog::OnIdle
)
2093 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog
, wxDialog
)
2095 #include "wx/editlbox.h"
2096 #include "wx/listctrl.h"
2098 // -----------------------------------------------------------------------
2100 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2102 // Repair focus - wxEditableListBox has bitmap buttons, which
2103 // get focus, and lose focus (into the oblivion) when they
2104 // become disabled due to change in control state.
2106 wxWindow
* lastFocused
= m_lastFocused
;
2107 wxWindow
* focus
= ::wxWindow::FindFocus();
2109 // If last focused control became disabled, set focus back to
2110 // wxEditableListBox
2111 if ( lastFocused
&& focus
!= lastFocused
&&
2112 lastFocused
->GetParent() == m_elbSubPanel
&&
2113 !lastFocused
->IsEnabled() )
2115 m_elb
->GetListCtrl()->SetFocus();
2118 m_lastFocused
= focus
;
2123 // -----------------------------------------------------------------------
2125 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2131 // -----------------------------------------------------------------------
2133 void wxPGArrayEditorDialog::Init()
2135 m_lastFocused
= NULL
;
2136 m_hasCustomNewAction
= false;
2137 m_itemPendingAtIndex
= -1;
2140 // -----------------------------------------------------------------------
2142 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow
*parent
,
2143 const wxString
& message
,
2144 const wxString
& caption
,
2151 Create(parent
,message
,caption
,style
,pos
,sz
);
2154 // -----------------------------------------------------------------------
2156 bool wxPGArrayEditorDialog::Create( wxWindow
*parent
,
2157 const wxString
& message
,
2158 const wxString
& caption
,
2163 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2164 // FIXME: This should be only a temporary fix.
2167 int useStyle
= wxCAPTION
;
2169 int useStyle
= style
;
2172 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2174 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2176 #if !wxPG_SMALL_SCREEN
2177 const int spacing
= 4;
2179 const int spacing
= 3;
2184 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2187 if ( message
.length() )
2188 topsizer
->Add( new wxStaticText(this,-1,message
),
2189 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2191 m_elb
= new wxEditableListBox(this, wxID_ANY
, message
,
2198 // Populate the list box
2200 for ( unsigned int i
=0; i
<ArrayGetCount(); i
++ )
2201 arr
.push_back(ArrayGet(i
));
2202 m_elb
->SetStrings(arr
);
2204 // Connect event handlers
2206 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2208 but
= m_elb
->GetNewButton();
2209 m_elbSubPanel
= but
->GetParent();
2210 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2211 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick
),
2214 but
= m_elb
->GetDelButton();
2215 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2216 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick
),
2219 but
= m_elb
->GetUpButton();
2220 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2221 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick
),
2224 but
= m_elb
->GetDownButton();
2225 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2226 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick
),
2229 lc
->Connect(lc
->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT
,
2230 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit
),
2233 topsizer
->Add( m_elb
, 1, wxEXPAND
, spacing
);
2235 // Standard dialog buttons
2236 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2237 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2238 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2239 buttonSizer
->Realize();
2240 topsizer
->Add( buttonSizer
, 0,
2241 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2246 SetSizer( topsizer
);
2247 topsizer
->SetSizeHints( this );
2249 #if !wxPG_SMALL_SCREEN
2250 if ( sz
.x
== wxDefaultSize
.x
&&
2251 sz
.y
== wxDefaultSize
.y
)
2252 SetSize( wxSize(275,360) );
2260 // -----------------------------------------------------------------------
2262 int wxPGArrayEditorDialog::GetSelection() const
2264 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2266 int index
= lc
->GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
2273 // -----------------------------------------------------------------------
2275 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent
& event
)
2277 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2278 int newItemIndex
= lc
->GetItemCount() - 1;
2280 if ( m_hasCustomNewAction
)
2283 if ( OnCustomNewAction(&str
) )
2285 if ( ArrayInsert(str
, newItemIndex
) )
2287 lc
->InsertItem(newItemIndex
, str
);
2292 // Do *not* skip the event! We do not want the wxEditableListBox
2297 m_itemPendingAtIndex
= newItemIndex
;
2303 // -----------------------------------------------------------------------
2305 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent
& event
)
2307 int index
= GetSelection();
2310 ArrayRemoveAt( index
);
2317 // -----------------------------------------------------------------------
2319 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent
& event
)
2321 int index
= GetSelection();
2324 ArraySwap(index
-1,index
);
2331 // -----------------------------------------------------------------------
2333 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent
& event
)
2335 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2336 int index
= GetSelection();
2337 int lastStringIndex
= lc
->GetItemCount() - 1;
2338 if ( index
>= 0 && index
< lastStringIndex
)
2340 ArraySwap(index
, index
+1);
2347 // -----------------------------------------------------------------------
2349 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent
& event
)
2351 wxString str
= event
.GetLabel();
2353 if ( m_itemPendingAtIndex
>= 0 )
2356 if ( ArrayInsert(str
, m_itemPendingAtIndex
) )
2362 // Editable list box doesn't really respect Veto(), but
2363 // it recognizes if no text was added, so we simulate
2365 event
.m_item
.SetText(wxEmptyString
);
2366 m_elb
->GetListCtrl()->SetItemText(m_itemPendingAtIndex
,
2374 // Change an existing item
2375 int index
= GetSelection();
2376 wxASSERT( index
!= wxNOT_FOUND
);
2377 if ( ArraySet(index
, str
) )
2386 #endif // wxUSE_EDITABLELISTBOX
2388 // -----------------------------------------------------------------------
2389 // wxPGArrayStringEditorDialog
2390 // -----------------------------------------------------------------------
2392 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2394 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2397 // -----------------------------------------------------------------------
2399 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2401 return m_array
[index
];
2404 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2406 return m_array
.size();
2409 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2414 m_array
.Insert(str
,index
);
2418 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2420 m_array
[index
] = str
;
2424 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2426 m_array
.RemoveAt(index
);
2429 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2431 wxString old_str
= m_array
[first
];
2432 wxString new_str
= m_array
[second
];
2433 m_array
[first
] = new_str
;
2434 m_array
[second
] = old_str
;
2437 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2438 : wxPGArrayEditorDialog()
2443 void wxPGArrayStringEditorDialog::Init()
2445 m_pCallingClass
= NULL
;
2449 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString
* resString
)
2451 return m_pCallingClass
->OnCustomStringEdit(m_parent
, *resString
);
2454 // -----------------------------------------------------------------------
2455 // wxArrayStringProperty
2456 // -----------------------------------------------------------------------
2458 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2459 wxPGProperty
, // Property we inherit from
2460 wxArrayString
, // Value type name
2461 const wxArrayString
&, // Value type, as given in constructor
2462 TextCtrlAndButton
) // Initial editor
2464 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2465 const wxString
& name
,
2466 const wxArrayString
& array
)
2467 : wxPGProperty(label
,name
)
2473 wxArrayStringProperty::~wxArrayStringProperty() { }
2475 void wxArrayStringProperty::OnSetValue()
2477 GenerateValueAsString();
2481 wxArrayStringProperty::ConvertArrayToString(const wxArrayString
& arr
,
2483 const wxUniChar
& delimiter
) const
2485 if ( delimiter
== '"' || delimiter
== '\'' )
2488 ArrayStringToString(*pString
,
2491 Escape
| QuoteStrings
);
2495 // Regular delimiter
2496 ArrayStringToString(*pString
,
2503 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2504 int argFlags
) const
2507 // If this is called from GetValueAsString(), return cached string
2508 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2513 wxArrayString arr
= m_value
.GetArrayString();
2515 ConvertArrayToString(arr
, &s
, m_delimiter
);
2519 // Converts wxArrayString to a string separated by delimeters and spaces.
2520 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2523 wxArrayStringProperty::ArrayStringToString( wxString
& dst
,
2524 const wxArrayString
& src
,
2525 wxUniChar delimiter
, int flags
)
2531 unsigned int itemCount
= src
.size();
2535 if ( flags
& Escape
)
2538 pdr
= wxS("\\") + static_cast<wchar_t>(delimiter
);
2542 dst
.append( preas
);
2544 wxString
delimStr(delimiter
);
2546 for ( i
= 0; i
< itemCount
; i
++ )
2548 wxString
str( src
.Item(i
) );
2550 // Do some character conversion.
2551 // Converts \ to \\ and $delimiter to \$delimiter
2552 // Useful when quoting.
2553 if ( flags
& Escape
)
2555 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2557 str
.Replace( preas
, pdr
, true );
2562 if ( i
< (itemCount
-1) )
2564 dst
.append( delimStr
);
2565 dst
.append( wxS(" ") );
2566 dst
.append( preas
);
2568 else if ( flags
& QuoteStrings
)
2569 dst
.append( delimStr
);
2573 void wxArrayStringProperty::GenerateValueAsString()
2575 wxArrayString arr
= m_value
.GetArrayString();
2576 ConvertArrayToString(arr
, &m_display
, m_delimiter
);
2579 // Default implementation doesn't do anything.
2580 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2585 wxPGArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2587 return new wxPGArrayStringEditorDialog();
2590 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2591 wxWindow
* WXUNUSED(primaryCtrl
),
2595 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2597 if ( !propGrid
->EditorValidate() )
2600 // Create editor dialog.
2601 wxPGArrayEditorDialog
* dlg
= CreateEditorDialog();
2602 #if wxUSE_VALIDATORS
2603 wxValidator
* validator
= GetValidator();
2604 wxPGInDialogValidator dialogValidator
;
2607 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2610 strEdDlg
->SetCustomButton(cbt
, this);
2612 dlg
->SetDialogValue( useValue
);
2613 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2615 #if !wxPG_SMALL_SCREEN
2616 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2625 int res
= dlg
->ShowModal();
2627 if ( res
== wxID_OK
&& dlg
->IsModified() )
2629 wxVariant value
= dlg
->GetDialogValue();
2630 if ( !value
.IsNull() )
2632 wxArrayString actualValue
= value
.GetArrayString();
2634 ConvertArrayToString(actualValue
, &tempStr
, m_delimiter
);
2635 #if wxUSE_VALIDATORS
2636 if ( dialogValidator
.DoValidate(propGrid
, validator
,
2640 SetValueInEvent( actualValue
);
2657 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2661 if ( propGrid
->IsMainButtonEvent(event
) )
2662 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2666 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
,
2667 const wxString
& text
, int ) const
2671 if ( m_delimiter
== '"' || m_delimiter
== '\'' )
2674 WX_PG_TOKENIZER2_BEGIN(text
, m_delimiter
)
2676 // Need to replace backslashes with empty characters
2677 // (opposite what is done in ConvertArrayToString()).
2678 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2682 WX_PG_TOKENIZER2_END()
2686 // Regular delimiter
2687 WX_PG_TOKENIZER1_BEGIN(text
, m_delimiter
)
2689 WX_PG_TOKENIZER1_END()
2697 bool wxArrayStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
2699 if ( name
== wxPG_ARRAY_DELIMITER
)
2701 m_delimiter
= value
.GetChar();
2702 GenerateValueAsString();
2708 // -----------------------------------------------------------------------
2709 // wxPGInDialogValidator
2710 // -----------------------------------------------------------------------
2712 #if wxUSE_VALIDATORS
2713 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2714 wxValidator
* validator
,
2715 const wxString
& value
)
2720 wxTextCtrl
* tc
= m_textCtrl
;
2725 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2726 wxPoint(30000,30000));
2733 tc
->SetValue(value
);
2735 validator
->SetWindow(tc
);
2736 bool res
= validator
->Validate(propGrid
);
2741 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2742 wxValidator
* WXUNUSED(validator
),
2743 const wxString
& WXUNUSED(value
) )
2749 // -----------------------------------------------------------------------
2751 #endif // wxUSE_PROPGRID