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
)
196 bool wxNumericPropertyValidator::Validate(wxWindow
* parent
)
198 if ( !wxTextValidator::Validate(parent
) )
201 wxWindow
* wnd
= GetWindow();
202 if ( !wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
205 // Do not allow zero-length string
206 wxTextCtrl
* tc
= static_cast<wxTextCtrl
*>(wnd
);
207 wxString text
= tc
->GetValue();
209 if ( !text
.length() )
215 #endif // wxUSE_VALIDATORS
217 // -----------------------------------------------------------------------
219 // -----------------------------------------------------------------------
221 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
224 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
225 long value
) : wxPGProperty(label
,name
)
230 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
231 const wxLongLong
& value
) : wxPGProperty(label
,name
)
233 SetValue(WXVARIANT(value
));
236 wxIntProperty::~wxIntProperty() { }
238 wxString
wxIntProperty::ValueToString( wxVariant
& value
,
239 int WXUNUSED(argFlags
) ) const
241 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
243 return wxString::Format(wxS("%li"),value
.GetLong());
245 else if ( value
.GetType() == wxPG_VARIANT_TYPE_LONGLONG
)
247 wxLongLong ll
= value
.GetLongLong();
248 return ll
.ToString();
251 return wxEmptyString
;
254 bool wxIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
259 if ( text
.length() == 0 )
265 // We know it is a number, but let's still check
267 if ( text
.IsNumber() )
269 // Remove leading zeroes, so that the number is not interpreted as octal
270 wxString::const_iterator i
= text
.begin();
271 wxString::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
273 int firstNonZeroPos
= 0;
275 for ( ; i
!= iMax
; ++i
)
278 if ( c
!= wxS('0') && c
!= wxS(' ') )
283 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
285 wxString variantType
= variant
.GetType();
286 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
288 wxLongLong_t value64
= 0;
290 if ( useText
.ToLongLong(&value64
, 10) &&
291 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
294 bool doChangeValue
= isPrevLong
;
296 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_LONGLONG
)
298 wxLongLong oldValue
= variant
.GetLongLong();
299 if ( oldValue
.GetValue() != value64
)
300 doChangeValue
= true;
305 wxLongLong
ll(value64
);
311 if ( useText
.ToLong( &value32
, 0 ) )
313 if ( !isPrevLong
|| variant
!= value32
)
320 else if ( argFlags
& wxPG_REPORT_ERROR
)
326 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
328 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
!= (long)value
)
330 variant
= (long)value
;
337 // Common validation code to be called in ValidateValue()
340 // Note that 'value' is reference on purpose, so we can write
341 // back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE.
344 bool NumericValidation( const wxPGProperty
* property
,
346 wxPGValidationInfo
* pValidationInfo
,
348 const wxString
& strFmt
)
350 T min
= (T
) wxINT64_MIN
;
351 T max
= (T
) wxINT64_MAX
;
356 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
357 if ( !variant
.IsNull() )
359 variant
.Convert(&min
);
363 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
364 if ( !variant
.IsNull() )
366 variant
.Convert(&max
);
374 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
377 wxString smin
= wxString::Format(strFmt
, min
);
378 wxString smax
= wxString::Format(strFmt
, max
);
380 msg
= wxString::Format(
381 _("Value must be %s or higher."),
384 msg
= wxString::Format(
385 _("Value must be between %s and %s."),
386 smin
.c_str(), smax
.c_str());
387 pValidationInfo
->SetFailureMessage(msg
);
389 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
392 value
= max
- (min
- value
);
401 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
404 wxString smin
= wxString::Format(strFmt
, min
);
405 wxString smax
= wxString::Format(strFmt
, max
);
407 msg
= wxString::Format(
408 _("Value must be %s or less."),
411 msg
= wxString::Format(
412 _("Value must be between %s and %s."),
413 smin
.c_str(), smax
.c_str());
414 pValidationInfo
->SetFailureMessage(msg
);
416 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
419 value
= min
+ (value
- max
);
426 bool wxIntProperty::DoValidation( const wxPGProperty
* property
,
428 wxPGValidationInfo
* pValidationInfo
,
431 return NumericValidation
<wxLongLong_t
>(property
,
438 bool wxIntProperty::ValidateValue( wxVariant
& value
,
439 wxPGValidationInfo
& validationInfo
) const
441 wxLongLong_t ll
= value
.GetLongLong().GetValue();
442 return DoValidation(this, ll
, &validationInfo
,
443 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
446 wxValidator
* wxIntProperty::GetClassValidator()
449 WX_PG_DOGETVALIDATOR_ENTRY()
451 wxValidator
* validator
= new wxNumericPropertyValidator(
452 wxNumericPropertyValidator::Signed
);
454 WX_PG_DOGETVALIDATOR_EXIT(validator
)
460 wxValidator
* wxIntProperty::DoGetValidator() const
462 return GetClassValidator();
465 // -----------------------------------------------------------------------
467 // -----------------------------------------------------------------------
470 #define wxPG_UINT_TEMPLATE_MAX 8
472 static const wxChar
* const gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
473 wxT("%x"),wxT("0x%x"),wxT("$%x"),
474 wxT("%X"),wxT("0x%X"),wxT("$%X"),
478 static const char* const gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
479 "%" wxLongLongFmtSpec
"x",
480 "0x%" wxLongLongFmtSpec
"x",
481 "$%" wxLongLongFmtSpec
"x",
482 "%" wxLongLongFmtSpec
"X",
483 "0x%" wxLongLongFmtSpec
"X",
484 "$%" wxLongLongFmtSpec
"X",
485 "%" wxLongLongFmtSpec
"u",
486 "%" wxLongLongFmtSpec
"o"
489 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
490 long,unsigned long,TextCtrl
)
492 void wxUIntProperty::Init()
494 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
496 m_prefix
= wxPG_PREFIX_NONE
;
499 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
500 unsigned long value
) : wxPGProperty(label
,name
)
503 SetValue((long)value
);
506 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
507 const wxULongLong
& value
) : wxPGProperty(label
,name
)
510 SetValue(WXVARIANT(value
));
513 wxUIntProperty::~wxUIntProperty() { }
515 wxString
wxUIntProperty::ValueToString( wxVariant
& value
,
516 int WXUNUSED(argFlags
) ) const
518 size_t index
= m_base
+ m_prefix
;
519 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
520 index
= wxPG_BASE_DEC
;
522 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
524 return wxString::Format(gs_uintTemplates32
[index
],
525 (unsigned long)value
.GetLong());
528 wxULongLong ull
= value
.GetULongLong();
530 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
533 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
535 wxString variantType
= variant
.GetType();
536 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
538 if ( text
.length() == 0 )
545 if ( text
[0] == wxS('$') )
548 wxULongLong_t value64
= 0;
549 wxString s
= text
.substr(start
, text
.length() - start
);
551 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
553 if ( value64
>= LONG_MAX
)
555 bool doChangeValue
= isPrevLong
;
557 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_ULONGLONG
)
559 wxULongLong oldValue
= variant
.GetULongLong();
560 if ( oldValue
.GetValue() != value64
)
561 doChangeValue
= true;
566 variant
= wxULongLong(value64
);
572 unsigned long value32
= wxLongLong(value64
).GetLo();
573 if ( !isPrevLong
|| m_value
!= (long)value32
)
575 variant
= (long)value32
;
584 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
586 if ( variant
!= (long)number
)
588 variant
= (long)number
;
594 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
596 wxULongLong_t uul
= value
.GetULongLong().GetValue();
598 NumericValidation
<wxULongLong_t
>(this,
601 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
,
605 wxValidator
* wxUIntProperty::DoGetValidator() const
608 WX_PG_DOGETVALIDATOR_ENTRY()
610 wxValidator
* validator
= new wxNumericPropertyValidator(
611 wxNumericPropertyValidator::Unsigned
,
614 WX_PG_DOGETVALIDATOR_EXIT(validator
)
620 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
622 if ( name
== wxPG_UINT_BASE
)
624 int val
= value
.GetLong();
626 m_realBase
= (wxByte
) val
;
627 if ( m_realBase
> 16 )
631 // Translate logical base to a template array index
633 if ( val
== wxPG_BASE_HEX
)
635 else if ( val
== wxPG_BASE_DEC
)
637 else if ( val
== wxPG_BASE_HEXL
)
641 else if ( name
== wxPG_UINT_PREFIX
)
643 m_prefix
= (wxByte
) value
.GetLong();
649 // -----------------------------------------------------------------------
651 // -----------------------------------------------------------------------
653 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
654 double,double,TextCtrl
)
656 wxFloatProperty::wxFloatProperty( const wxString
& label
,
657 const wxString
& name
,
659 : wxPGProperty(label
,name
)
665 wxFloatProperty::~wxFloatProperty() { }
667 // This helper method provides standard way for floating point-using
668 // properties to convert values to string.
669 const wxString
& wxPropertyGrid::DoubleToString(wxString
& target
,
673 wxString
* precTemplate
)
675 if ( precision
>= 0 )
679 precTemplate
= &text1
;
681 if ( !precTemplate
->length() )
683 *precTemplate
= wxS("%.");
684 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
685 *precTemplate
<< wxS('f');
688 target
.Printf( precTemplate
->c_str(), value
);
692 target
.Printf( wxS("%f"), value
);
695 if ( removeZeroes
&& precision
!= 0 && target
.length() )
697 // Remove excess zeroes (do not remove this code just yet,
698 // since sprintf can't do the same consistently across platforms).
699 wxString::const_iterator i
= target
.end() - 1;
700 size_t new_len
= target
.length() - 1;
702 for ( ; i
!= target
.begin(); --i
)
704 if ( *i
!= wxS('0') )
709 wxChar cur_char
= *i
;
710 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
713 if ( new_len
!= target
.length() )
714 target
.resize(new_len
);
717 // Remove sign from zero
718 if ( target
.length() >= 2 && target
[0] == wxS('-') )
721 wxString::const_iterator i
= target
.begin() + 1;
723 for ( ; i
!= target
.end(); i
++ )
725 if ( *i
!= wxS('0') && *i
!= wxS('.') && *i
!= wxS(',') )
733 target
.erase(target
.begin());
739 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
743 if ( !value
.IsNull() )
745 wxPropertyGrid::DoubleToString(text
,
748 !(argFlags
& wxPG_FULL_VALUE
),
754 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
759 if ( text
.length() == 0 )
765 bool res
= text
.ToDouble(&value
);
768 if ( variant
!= value
)
774 else if ( argFlags
& wxPG_REPORT_ERROR
)
780 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
782 wxPGValidationInfo
* pValidationInfo
,
785 return NumericValidation
<double>(property
,
793 wxFloatProperty::ValidateValue( wxVariant
& value
,
794 wxPGValidationInfo
& validationInfo
) const
796 double fpv
= value
.GetDouble();
797 return DoValidation(this, fpv
, &validationInfo
,
798 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
801 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
803 if ( name
== wxPG_FLOAT_PRECISION
)
805 m_precision
= value
.GetLong();
812 wxFloatProperty::GetClassValidator()
815 WX_PG_DOGETVALIDATOR_ENTRY()
817 wxValidator
* validator
= new wxNumericPropertyValidator(
818 wxNumericPropertyValidator::Float
);
820 WX_PG_DOGETVALIDATOR_EXIT(validator
)
826 wxValidator
* wxFloatProperty::DoGetValidator() const
828 return GetClassValidator();
831 // -----------------------------------------------------------------------
833 // -----------------------------------------------------------------------
835 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
836 // there is a custom GetEditorClass.
838 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
840 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
842 // Select correct editor control.
843 #if wxPG_INCLUDE_CHECKBOX
844 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
845 return wxPGEditor_Choice
;
846 return wxPGEditor_CheckBox
;
848 return wxPGEditor_Choice
;
852 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
853 wxPGProperty(label
,name
)
855 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
857 SetValue(wxPGVariant_Bool(value
));
859 m_flags
|= wxPG_PROP_USE_DCC
;
862 wxBoolProperty::~wxBoolProperty() { }
864 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
867 bool boolValue
= value
.GetBool();
869 // As a fragment of composite string value,
870 // make it a little more readable.
871 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
879 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
880 return wxEmptyString
;
883 if ( wxPGGlobalVars
->m_autoGetTranslation
)
884 notFmt
= _("Not %s");
886 notFmt
= wxS("Not %s");
888 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
892 if ( !(argFlags
& wxPG_FULL_VALUE
) )
894 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
899 if ( boolValue
) text
= wxS("true");
900 else text
= wxS("false");
905 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
907 bool boolValue
= false;
908 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
909 text
.CmpNoCase(wxS("true")) == 0 ||
910 text
.CmpNoCase(m_label
) == 0 )
913 if ( text
.length() == 0 )
919 if ( variant
!= boolValue
)
921 variant
= wxPGVariant_Bool(boolValue
);
927 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
929 bool boolValue
= value
? true : false;
931 if ( variant
!= boolValue
)
933 variant
= wxPGVariant_Bool(boolValue
);
939 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
941 #if wxPG_INCLUDE_CHECKBOX
942 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
944 if ( value
.GetLong() )
945 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
947 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
951 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
953 if ( value
.GetLong() )
954 m_flags
|= wxPG_PROP_USE_DCC
;
956 m_flags
&= ~(wxPG_PROP_USE_DCC
);
962 // -----------------------------------------------------------------------
964 // -----------------------------------------------------------------------
966 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
968 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
970 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
971 const long* values
, int value
) : wxPGProperty(label
,name
)
977 m_choices
.Add(labels
,values
);
979 if ( GetItemCount() )
980 SetValue( (long)value
);
984 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
985 const long* values
, wxPGChoices
* choicesCache
, int value
)
986 : wxPGProperty(label
,name
)
990 wxASSERT( choicesCache
);
992 if ( choicesCache
->IsOk() )
994 m_choices
.Assign( *choicesCache
);
995 m_value
= wxPGVariant_Zero
;
999 m_choices
.Add(labels
,values
);
1001 if ( GetItemCount() )
1002 SetValue( (long)value
);
1006 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1007 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1008 : wxPGProperty(label
,name
)
1012 if ( &labels
&& labels
.size() )
1014 m_choices
.Set(labels
, values
);
1016 if ( GetItemCount() )
1017 SetValue( (long)value
);
1021 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1022 wxPGChoices
& choices
, int value
)
1023 : wxPGProperty(label
,name
)
1025 m_choices
.Assign( choices
);
1027 if ( GetItemCount() )
1028 SetValue( (long)value
);
1031 int wxEnumProperty::GetIndexForValue( int value
) const
1033 if ( !m_choices
.IsOk() )
1036 int intVal
= m_choices
.Index(value
);
1043 wxEnumProperty::~wxEnumProperty ()
1047 int wxEnumProperty::ms_nextIndex
= -2;
1049 void wxEnumProperty::OnSetValue()
1051 wxString variantType
= m_value
.GetType();
1053 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
1055 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
1057 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
1059 ValueFromString_( m_value
, m_value
.GetString(), 0 );
1066 if ( ms_nextIndex
!= -2 )
1068 m_index
= ms_nextIndex
;
1073 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
1075 // Make sure string value is in the list,
1076 // unless property has string as preferred value type
1077 // To reduce code size, use conversion here as well
1078 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
1079 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
1080 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
1085 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
1086 int WXUNUSED(argFlags
) ) const
1088 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
1089 return value
.GetString();
1091 int index
= m_choices
.Index(value
.GetLong());
1093 return wxEmptyString
;
1095 return m_choices
.GetLabel(index
);
1098 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1100 return ValueFromString_( variant
, text
, argFlags
);
1103 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
1105 return ValueFromInt_( variant
, intVal
, argFlags
);
1108 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
1113 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
1115 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
1116 if ( text
.CmpNoCase(entryLabel
) == 0 )
1119 useValue
= m_choices
.GetValue(i
);
1124 bool asText
= false;
1126 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
1128 // If text not any of the choices, store as text instead
1129 // (but only if we are wxEditEnumProperty)
1130 if ( useIndex
== -1 && isEdit
)
1135 int setAsNextIndex
= -2;
1139 setAsNextIndex
= -1;
1142 else if ( useIndex
!= GetIndex() )
1144 if ( useIndex
!= -1 )
1146 setAsNextIndex
= useIndex
;
1147 value
= (long)useValue
;
1151 setAsNextIndex
= -1;
1152 value
= wxPGVariant_MinusOne
;
1156 if ( setAsNextIndex
!= -2 )
1158 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1159 // validation purposes only, and index must not be changed
1160 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1161 ms_nextIndex
= setAsNextIndex
;
1163 if ( isEdit
|| setAsNextIndex
!= -1 )
1171 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1173 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1177 if ( argFlags
& wxPG_FULL_VALUE
)
1179 ms_nextIndex
= GetIndexForValue( intVal
);
1183 if ( intVal
!= GetIndex() )
1185 ms_nextIndex
= intVal
;
1189 if ( ms_nextIndex
!= -2 )
1191 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1192 intVal
= m_choices
.GetValue(intVal
);
1194 variant
= (long)intVal
;
1203 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1209 void wxEnumProperty::SetIndex( int index
)
1215 int wxEnumProperty::GetIndex() const
1217 if ( m_value
.IsNull() )
1220 if ( ms_nextIndex
!= -2 )
1221 return ms_nextIndex
;
1226 // -----------------------------------------------------------------------
1227 // wxEditEnumProperty
1228 // -----------------------------------------------------------------------
1230 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1232 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1234 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1235 const long* values
, const wxString
& value
)
1236 : wxEnumProperty(label
,name
,labels
,values
,0)
1241 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1242 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1243 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1248 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1249 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1250 : wxEnumProperty(label
,name
,labels
,values
,0)
1255 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1256 wxPGChoices
& choices
, const wxString
& value
)
1257 : wxEnumProperty(label
,name
,choices
,0)
1262 wxEditEnumProperty::~wxEditEnumProperty()
1266 // -----------------------------------------------------------------------
1268 // -----------------------------------------------------------------------
1270 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1272 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1274 void wxFlagsProperty::Init()
1276 long value
= m_value
;
1279 // Generate children
1283 unsigned int prevChildCount
= m_children
.size();
1286 if ( prevChildCount
)
1288 wxPropertyGridPageState
* state
= GetParentState();
1290 // State safety check (it may be NULL in immediate parent)
1295 wxPGProperty
* selected
= state
->GetSelection();
1298 if ( selected
->GetParent() == this )
1299 oldSel
= selected
->GetIndexInParent();
1300 else if ( selected
== this )
1304 state
->DoClearSelection();
1307 // Delete old children
1308 for ( i
=0; i
<prevChildCount
; i
++ )
1309 delete m_children
[i
];
1313 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1314 // to child bool property controls.
1315 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1316 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1319 if ( m_choices
.IsOk() )
1321 const wxPGChoices
& choices
= m_choices
;
1323 for ( i
=0; i
<GetItemCount(); i
++ )
1326 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1328 wxPGProperty
* boolProp
;
1329 wxString label
= GetLabel(i
);
1332 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1334 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1339 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1341 if ( attrUseCheckBox
)
1342 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1345 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1347 AddPrivateChild(boolProp
);
1350 m_oldChoicesData
= m_choices
.GetDataPtr();
1353 m_oldValue
= m_value
;
1355 if ( prevChildCount
)
1356 SubPropsChanged(oldSel
);
1359 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1360 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1362 m_oldChoicesData
= NULL
;
1366 m_choices
.Set(labels
,values
);
1368 wxASSERT( GetItemCount() );
1374 m_value
= wxPGVariant_Zero
;
1378 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1379 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1380 : wxPGProperty(label
,name
)
1382 m_oldChoicesData
= NULL
;
1384 if ( &labels
&& labels
.size() )
1386 m_choices
.Set(labels
,values
);
1388 wxASSERT( GetItemCount() );
1390 SetValue( (long)value
);
1394 m_value
= wxPGVariant_Zero
;
1398 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1399 wxPGChoices
& choices
, long value
)
1400 : wxPGProperty(label
,name
)
1402 m_oldChoicesData
= NULL
;
1404 if ( choices
.IsOk() )
1406 m_choices
.Assign(choices
);
1408 wxASSERT( GetItemCount() );
1414 m_value
= wxPGVariant_Zero
;
1418 wxFlagsProperty::~wxFlagsProperty()
1422 void wxFlagsProperty::OnSetValue()
1424 if ( !m_choices
.IsOk() || !GetItemCount() )
1426 m_value
= wxPGVariant_Zero
;
1430 long val
= m_value
.GetLong();
1434 // normalize the value (i.e. remove extra flags)
1436 const wxPGChoices
& choices
= m_choices
;
1437 for ( i
= 0; i
< GetItemCount(); i
++ )
1439 fullFlags
|= choices
.GetValue(i
);
1446 // Need to (re)init now?
1447 if ( GetChildCount() != GetItemCount() ||
1448 m_choices
.GetDataPtr() != m_oldChoicesData
)
1454 long newFlags
= m_value
;
1456 if ( newFlags
!= m_oldValue
)
1458 // Set child modified states
1460 const wxPGChoices
& choices
= m_choices
;
1461 for ( i
= 0; i
<GetItemCount(); i
++ )
1465 flag
= choices
.GetValue(i
);
1467 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1468 Item(i
)->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1471 m_oldValue
= newFlags
;
1475 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1476 int WXUNUSED(argFlags
) ) const
1480 if ( !m_choices
.IsOk() )
1485 const wxPGChoices
& choices
= m_choices
;
1487 for ( i
= 0; i
< GetItemCount(); i
++ )
1490 doAdd
= ( flags
& choices
.GetValue(i
) );
1494 text
+= choices
.GetLabel(i
);
1499 // remove last comma
1500 if ( text
.Len() > 1 )
1501 text
.Truncate ( text
.Len() - 2 );
1506 // Translate string into flag tokens
1507 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1509 if ( !m_choices
.IsOk() )
1514 // semicolons are no longer valid delimeters
1515 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1517 if ( token
.length() )
1519 // Determine which one it is
1520 long bit
= IdToBit( token
);
1533 WX_PG_TOKENIZER1_END()
1535 if ( variant
!= (long)newFlags
)
1537 variant
= (long)newFlags
;
1544 // Converts string id to a relevant bit.
1545 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1548 for ( i
= 0; i
< GetItemCount(); i
++ )
1550 if ( id
== GetLabel(i
) )
1552 return m_choices
.GetValue(i
);
1558 void wxFlagsProperty::RefreshChildren()
1560 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1562 int flags
= m_value
.GetLong();
1564 const wxPGChoices
& choices
= m_choices
;
1566 for ( i
= 0; i
< GetItemCount(); i
++ )
1570 flag
= choices
.GetValue(i
);
1572 long subVal
= flags
& flag
;
1573 wxPGProperty
* p
= Item(i
);
1575 if ( subVal
!= (m_oldValue
& flag
) )
1576 p
->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1578 p
->SetValue( subVal
?true:false );
1584 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1586 wxVariant
& childValue
) const
1588 long oldValue
= thisValue
.GetLong();
1589 long val
= childValue
.GetLong();
1590 unsigned long vi
= m_choices
.GetValue(childIndex
);
1593 return (long) (oldValue
| vi
);
1595 return (long) (oldValue
& ~(vi
));
1598 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1600 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1601 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1603 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1605 Item(i
)->SetAttribute(name
, value
);
1607 // Must return false so that the attribute is stored in
1608 // flag property's actual property storage
1614 // -----------------------------------------------------------------------
1616 // -----------------------------------------------------------------------
1618 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1620 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1621 : wxLongStringProperty(name
,label
,value
)
1623 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1626 wxDirProperty::~wxDirProperty() { }
1628 wxValidator
* wxDirProperty::DoGetValidator() const
1630 return wxFileProperty::GetClassValidator();
1633 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1635 // Update property value from editor, if necessary
1636 wxSize
dlg_sz(300,400);
1638 wxString
dlgMessage(m_dlgMessage
);
1639 if ( dlgMessage
.empty() )
1640 dlgMessage
= _("Choose a directory:");
1641 wxDirDialog
dlg( propGrid
,
1645 #if !wxPG_SMALL_SCREEN
1646 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1654 if ( dlg
.ShowModal() == wxID_OK
)
1656 value
= dlg
.GetPath();
1662 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1664 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1666 m_dlgMessage
= value
.GetString();
1672 // -----------------------------------------------------------------------
1673 // wxPGFileDialogAdapter
1674 // -----------------------------------------------------------------------
1676 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1678 wxFileProperty
* fileProp
= NULL
;
1682 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1684 fileProp
= ((wxFileProperty
*)property
);
1685 wxFileName filename
= fileProp
->GetValue().GetString();
1686 path
= filename
.GetPath();
1687 indFilter
= fileProp
->m_indFilter
;
1689 if ( !path
.length() && fileProp
->m_basePath
.length() )
1690 path
= fileProp
->m_basePath
;
1694 wxFileName
fn(property
->GetValue().GetString());
1695 path
= fn
.GetPath();
1698 wxFileDialog
dlg( propGrid
->GetPanel(),
1699 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1700 property
->GetAttribute(wxS("InitialPath"), path
),
1702 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1704 wxDefaultPosition
);
1706 if ( indFilter
>= 0 )
1707 dlg
.SetFilterIndex( indFilter
);
1709 if ( dlg
.ShowModal() == wxID_OK
)
1712 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1713 SetValue( dlg
.GetPath() );
1719 // -----------------------------------------------------------------------
1721 // -----------------------------------------------------------------------
1723 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1724 wxString
,const wxString
&,TextCtrlAndButton
)
1726 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1727 const wxString
& value
) : wxPGProperty(label
,name
)
1729 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1731 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1736 wxFileProperty::~wxFileProperty() {}
1738 wxValidator
* wxFileProperty::GetClassValidator()
1740 #if wxUSE_VALIDATORS
1741 WX_PG_DOGETVALIDATOR_ENTRY()
1743 // Atleast wxPython 2.6.2.1 required that the string argument is given
1745 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1747 wxArrayString exChars
;
1748 exChars
.Add(wxS("?"));
1749 exChars
.Add(wxS("*"));
1750 exChars
.Add(wxS("|"));
1751 exChars
.Add(wxS("<"));
1752 exChars
.Add(wxS(">"));
1753 exChars
.Add(wxS("\""));
1755 validator
->SetExcludes(exChars
);
1757 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1763 wxValidator
* wxFileProperty::DoGetValidator() const
1765 return GetClassValidator();
1768 void wxFileProperty::OnSetValue()
1770 const wxString
& fnstr
= m_value
.GetString();
1772 wxFileName filename
= fnstr
;
1774 if ( !filename
.HasName() )
1776 m_value
= wxPGVariant_EmptyString
;
1779 // Find index for extension.
1780 if ( m_indFilter
< 0 && fnstr
.length() )
1782 wxString ext
= filename
.GetExt();
1785 size_t len
= m_wildcard
.length();
1787 pos
= m_wildcard
.find(wxS("|"), pos
);
1788 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1790 size_t ext_begin
= pos
+ 3;
1792 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1793 if ( pos
== wxString::npos
)
1795 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1797 if ( found_ext
.length() > 0 )
1799 if ( found_ext
[0] == wxS('*') )
1801 m_indFilter
= curind
;
1804 if ( ext
.CmpNoCase(found_ext
) == 0 )
1806 m_indFilter
= curind
;
1812 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1819 wxFileName
wxFileProperty::GetFileName() const
1821 wxFileName filename
;
1823 if ( !m_value
.IsNull() )
1824 filename
= m_value
.GetString();
1829 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1830 int argFlags
) const
1832 wxFileName filename
= value
.GetString();
1834 if ( !filename
.HasName() )
1835 return wxEmptyString
;
1837 wxString fullName
= filename
.GetFullName();
1838 if ( !fullName
.length() )
1839 return wxEmptyString
;
1841 if ( argFlags
& wxPG_FULL_VALUE
)
1843 return filename
.GetFullPath();
1845 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1847 if ( m_basePath
.Length() )
1849 wxFileName
fn2(filename
);
1850 fn2
.MakeRelativeTo(m_basePath
);
1851 return fn2
.GetFullPath();
1853 return filename
.GetFullPath();
1856 return filename
.GetFullName();
1859 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1861 return new wxPGFileDialogAdapter();
1864 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1866 wxFileName filename
= variant
.GetString();
1868 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1870 if ( filename
!= text
)
1878 if ( filename
.GetFullName() != text
)
1880 wxFileName fn
= filename
;
1881 fn
.SetFullName(text
);
1882 variant
= fn
.GetFullPath();
1890 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1892 // Return false on some occasions to make sure those attribs will get
1893 // stored in m_attributes.
1894 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1896 if ( value
.GetLong() )
1897 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1899 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1902 else if ( name
== wxPG_FILE_WILDCARD
)
1904 m_wildcard
= value
.GetString();
1906 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1908 m_basePath
= value
.GetString();
1910 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1911 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1913 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1915 m_initialPath
= value
.GetString();
1918 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1920 m_dlgTitle
= value
.GetString();
1926 // -----------------------------------------------------------------------
1927 // wxPGLongStringDialogAdapter
1928 // -----------------------------------------------------------------------
1930 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1932 wxString val1
= property
->GetValueAsString(0);
1933 wxString val_orig
= val1
;
1936 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1937 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1939 value
= wxString(val1
);
1941 // Run editor dialog.
1942 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1944 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1945 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1949 if ( val1
!= val_orig
)
1958 // -----------------------------------------------------------------------
1959 // wxLongStringProperty
1960 // -----------------------------------------------------------------------
1962 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1963 wxString
,const wxString
&,TextCtrlAndButton
)
1965 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1966 const wxString
& value
) : wxPGProperty(label
,name
)
1971 wxLongStringProperty::~wxLongStringProperty() {}
1973 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1974 int WXUNUSED(argFlags
) ) const
1979 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1982 if ( propGrid
->IsMainButtonEvent(event
) )
1985 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1987 wxString val1
= useValue
.GetString();
1988 wxString val_orig
= val1
;
1991 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1992 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1994 value
= wxString(val1
);
1996 // Run editor dialog.
1997 if ( OnButtonClick(propGrid
,value
) )
1999 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
2000 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
2004 if ( val1
!= val_orig
)
2006 SetValueInEvent( val1
);
2014 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
2016 return DisplayEditorDialog(this, propGrid
, value
);
2019 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
2022 // launch editor dialog
2023 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
2024 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
2026 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
2028 // Multi-line text editor dialog.
2029 #if !wxPG_SMALL_SCREEN
2030 const int spacing
= 8;
2032 const int spacing
= 4;
2034 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2035 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2036 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
2037 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
2039 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
2040 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
2042 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2043 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
2044 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
2045 buttonSizer
->Realize();
2046 topsizer
->Add( buttonSizer
, 0,
2047 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
2050 dlg
->SetSizer( topsizer
);
2051 topsizer
->SetSizeHints( dlg
);
2053 #if !wxPG_SMALL_SCREEN
2054 dlg
->SetSize(400,300);
2056 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
2059 int res
= dlg
->ShowModal();
2061 if ( res
== wxID_OK
)
2063 value
= ed
->GetValue();
2071 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2073 if ( variant
!= text
)
2081 #if wxUSE_EDITABLELISTBOX
2083 // -----------------------------------------------------------------------
2084 // wxPGArrayEditorDialog
2085 // -----------------------------------------------------------------------
2087 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog
, wxDialog
)
2088 EVT_IDLE(wxPGArrayEditorDialog::OnIdle
)
2091 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog
, wxDialog
)
2093 #include "wx/editlbox.h"
2094 #include "wx/listctrl.h"
2096 // -----------------------------------------------------------------------
2098 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2100 // Repair focus - wxEditableListBox has bitmap buttons, which
2101 // get focus, and lose focus (into the oblivion) when they
2102 // become disabled due to change in control state.
2104 wxWindow
* lastFocused
= m_lastFocused
;
2105 wxWindow
* focus
= ::wxWindow::FindFocus();
2107 // If last focused control became disabled, set focus back to
2108 // wxEditableListBox
2109 if ( lastFocused
&& focus
!= lastFocused
&&
2110 lastFocused
->GetParent() == m_elbSubPanel
&&
2111 !lastFocused
->IsEnabled() )
2113 m_elb
->GetListCtrl()->SetFocus();
2116 m_lastFocused
= focus
;
2121 // -----------------------------------------------------------------------
2123 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2129 // -----------------------------------------------------------------------
2131 void wxPGArrayEditorDialog::Init()
2133 m_lastFocused
= NULL
;
2134 m_hasCustomNewAction
= false;
2135 m_itemPendingAtIndex
= -1;
2138 // -----------------------------------------------------------------------
2140 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow
*parent
,
2141 const wxString
& message
,
2142 const wxString
& caption
,
2149 Create(parent
,message
,caption
,style
,pos
,sz
);
2152 // -----------------------------------------------------------------------
2154 bool wxPGArrayEditorDialog::Create( wxWindow
*parent
,
2155 const wxString
& message
,
2156 const wxString
& caption
,
2161 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2162 // FIXME: This should be only a temporary fix.
2165 int useStyle
= wxCAPTION
;
2167 int useStyle
= style
;
2170 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2172 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2174 #if !wxPG_SMALL_SCREEN
2175 const int spacing
= 4;
2177 const int spacing
= 3;
2182 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2185 if ( message
.length() )
2186 topsizer
->Add( new wxStaticText(this,-1,message
),
2187 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2189 m_elb
= new wxEditableListBox(this, wxID_ANY
, message
,
2196 // Populate the list box
2198 for ( unsigned int i
=0; i
<ArrayGetCount(); i
++ )
2199 arr
.push_back(ArrayGet(i
));
2200 m_elb
->SetStrings(arr
);
2202 // Connect event handlers
2204 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2206 but
= m_elb
->GetNewButton();
2207 m_elbSubPanel
= but
->GetParent();
2208 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2209 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick
),
2212 but
= m_elb
->GetDelButton();
2213 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2214 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick
),
2217 but
= m_elb
->GetUpButton();
2218 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2219 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick
),
2222 but
= m_elb
->GetDownButton();
2223 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2224 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick
),
2227 lc
->Connect(lc
->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT
,
2228 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit
),
2231 topsizer
->Add( m_elb
, 1, wxEXPAND
, spacing
);
2233 // Standard dialog buttons
2234 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2235 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2236 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2237 buttonSizer
->Realize();
2238 topsizer
->Add( buttonSizer
, 0,
2239 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2244 SetSizer( topsizer
);
2245 topsizer
->SetSizeHints( this );
2247 #if !wxPG_SMALL_SCREEN
2248 if ( sz
.x
== wxDefaultSize
.x
&&
2249 sz
.y
== wxDefaultSize
.y
)
2250 SetSize( wxSize(275,360) );
2258 // -----------------------------------------------------------------------
2260 int wxPGArrayEditorDialog::GetSelection() const
2262 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2264 int index
= lc
->GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
2271 // -----------------------------------------------------------------------
2273 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent
& event
)
2275 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2276 int newItemIndex
= lc
->GetItemCount() - 1;
2278 if ( m_hasCustomNewAction
)
2281 if ( OnCustomNewAction(&str
) )
2283 if ( ArrayInsert(str
, newItemIndex
) )
2285 lc
->InsertItem(newItemIndex
, str
);
2290 // Do *not* skip the event! We do not want the wxEditableListBox
2295 m_itemPendingAtIndex
= newItemIndex
;
2301 // -----------------------------------------------------------------------
2303 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent
& event
)
2305 int index
= GetSelection();
2308 ArrayRemoveAt( index
);
2315 // -----------------------------------------------------------------------
2317 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent
& event
)
2319 int index
= GetSelection();
2322 ArraySwap(index
-1,index
);
2329 // -----------------------------------------------------------------------
2331 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent
& event
)
2333 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2334 int index
= GetSelection();
2335 int lastStringIndex
= lc
->GetItemCount() - 1;
2336 if ( index
>= 0 && index
< lastStringIndex
)
2338 ArraySwap(index
, index
+1);
2345 // -----------------------------------------------------------------------
2347 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent
& event
)
2349 wxString str
= event
.GetLabel();
2351 if ( m_itemPendingAtIndex
>= 0 )
2354 if ( ArrayInsert(str
, m_itemPendingAtIndex
) )
2360 // Editable list box doesn't really respect Veto(), but
2361 // it recognizes if no text was added, so we simulate
2363 event
.m_item
.SetText(wxEmptyString
);
2364 m_elb
->GetListCtrl()->SetItemText(m_itemPendingAtIndex
,
2372 // Change an existing item
2373 int index
= GetSelection();
2374 wxASSERT( index
!= wxNOT_FOUND
);
2375 if ( ArraySet(index
, str
) )
2384 #endif // wxUSE_EDITABLELISTBOX
2386 // -----------------------------------------------------------------------
2387 // wxPGArrayStringEditorDialog
2388 // -----------------------------------------------------------------------
2390 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2392 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2395 // -----------------------------------------------------------------------
2397 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2399 return m_array
[index
];
2402 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2404 return m_array
.size();
2407 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2412 m_array
.Insert(str
,index
);
2416 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2418 m_array
[index
] = str
;
2422 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2424 m_array
.RemoveAt(index
);
2427 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2429 wxString old_str
= m_array
[first
];
2430 wxString new_str
= m_array
[second
];
2431 m_array
[first
] = new_str
;
2432 m_array
[second
] = old_str
;
2435 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2436 : wxPGArrayEditorDialog()
2441 void wxPGArrayStringEditorDialog::Init()
2443 m_pCallingClass
= NULL
;
2447 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString
* resString
)
2449 return m_pCallingClass
->OnCustomStringEdit(m_parent
, *resString
);
2452 // -----------------------------------------------------------------------
2453 // wxArrayStringProperty
2454 // -----------------------------------------------------------------------
2456 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2457 wxPGProperty
, // Property we inherit from
2458 wxArrayString
, // Value type name
2459 const wxArrayString
&, // Value type, as given in constructor
2460 TextCtrlAndButton
) // Initial editor
2462 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2463 const wxString
& name
,
2464 const wxArrayString
& array
)
2465 : wxPGProperty(label
,name
)
2471 wxArrayStringProperty::~wxArrayStringProperty() { }
2473 void wxArrayStringProperty::OnSetValue()
2475 GenerateValueAsString();
2479 wxArrayStringProperty::ConvertArrayToString(const wxArrayString
& arr
,
2481 const wxUniChar
& delimiter
) const
2483 if ( delimiter
== '"' || delimiter
== '\'' )
2486 ArrayStringToString(*pString
,
2489 Escape
| QuoteStrings
);
2493 // Regular delimiter
2494 ArrayStringToString(*pString
,
2501 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2502 int argFlags
) const
2505 // If this is called from GetValueAsString(), return cached string
2506 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2511 wxArrayString arr
= m_value
.GetArrayString();
2513 ConvertArrayToString(arr
, &s
, m_delimiter
);
2517 // Converts wxArrayString to a string separated by delimeters and spaces.
2518 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2521 wxArrayStringProperty::ArrayStringToString( wxString
& dst
,
2522 const wxArrayString
& src
,
2523 wxUniChar delimiter
, int flags
)
2529 unsigned int itemCount
= src
.size();
2533 if ( flags
& Escape
)
2536 pdr
= wxS("\\") + static_cast<wchar_t>(delimiter
);
2540 dst
.append( preas
);
2542 wxString
delimStr(delimiter
);
2544 for ( i
= 0; i
< itemCount
; i
++ )
2546 wxString
str( src
.Item(i
) );
2548 // Do some character conversion.
2549 // Converts \ to \\ and $delimiter to \$delimiter
2550 // Useful when quoting.
2551 if ( flags
& Escape
)
2553 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2555 str
.Replace( preas
, pdr
, true );
2560 if ( i
< (itemCount
-1) )
2562 dst
.append( delimStr
);
2563 dst
.append( wxS(" ") );
2564 dst
.append( preas
);
2566 else if ( flags
& QuoteStrings
)
2567 dst
.append( delimStr
);
2571 void wxArrayStringProperty::GenerateValueAsString()
2573 wxArrayString arr
= m_value
.GetArrayString();
2574 ConvertArrayToString(arr
, &m_display
, m_delimiter
);
2577 // Default implementation doesn't do anything.
2578 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2583 wxPGArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2585 return new wxPGArrayStringEditorDialog();
2588 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2589 wxWindow
* WXUNUSED(primaryCtrl
),
2593 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2595 if ( !propGrid
->EditorValidate() )
2598 // Create editor dialog.
2599 wxPGArrayEditorDialog
* dlg
= CreateEditorDialog();
2600 #if wxUSE_VALIDATORS
2601 wxValidator
* validator
= GetValidator();
2602 wxPGInDialogValidator dialogValidator
;
2605 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2608 strEdDlg
->SetCustomButton(cbt
, this);
2610 dlg
->SetDialogValue( useValue
);
2611 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2613 #if !wxPG_SMALL_SCREEN
2614 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2623 int res
= dlg
->ShowModal();
2625 if ( res
== wxID_OK
&& dlg
->IsModified() )
2627 wxVariant value
= dlg
->GetDialogValue();
2628 if ( !value
.IsNull() )
2630 wxArrayString actualValue
= value
.GetArrayString();
2632 ConvertArrayToString(actualValue
, &tempStr
, m_delimiter
);
2633 #if wxUSE_VALIDATORS
2634 if ( dialogValidator
.DoValidate(propGrid
, validator
,
2638 SetValueInEvent( actualValue
);
2655 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2659 if ( propGrid
->IsMainButtonEvent(event
) )
2660 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2664 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
,
2665 const wxString
& text
, int ) const
2669 if ( m_delimiter
== '"' || m_delimiter
== '\'' )
2672 WX_PG_TOKENIZER2_BEGIN(text
, m_delimiter
)
2674 // Need to replace backslashes with empty characters
2675 // (opposite what is done in ConvertArrayToString()).
2676 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2680 WX_PG_TOKENIZER2_END()
2684 // Regular delimiter
2685 WX_PG_TOKENIZER1_BEGIN(text
, m_delimiter
)
2687 WX_PG_TOKENIZER1_END()
2695 bool wxArrayStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
2697 if ( name
== wxPG_ARRAY_DELIMITER
)
2699 m_delimiter
= value
.GetChar();
2700 GenerateValueAsString();
2706 // -----------------------------------------------------------------------
2707 // wxPGInDialogValidator
2708 // -----------------------------------------------------------------------
2710 #if wxUSE_VALIDATORS
2711 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2712 wxValidator
* validator
,
2713 const wxString
& value
)
2718 wxTextCtrl
* tc
= m_textCtrl
;
2723 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2724 wxPoint(30000,30000));
2731 tc
->SetValue(value
);
2733 validator
->SetWindow(tc
);
2734 bool res
= validator
->Validate(propGrid
);
2739 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2740 wxValidator
* WXUNUSED(validator
),
2741 const wxString
& WXUNUSED(value
) )
2747 // -----------------------------------------------------------------------
2749 #endif // wxUSE_PROPGRID