1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/props.cpp
3 // Purpose: Basic Property Classes
4 // Author: Jaakko Salli
7 // Copyright: (c) Jaakko Salli
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
22 #include "wx/object.h"
24 #include "wx/string.h"
27 #include "wx/window.h"
30 #include "wx/dcclient.h"
31 #include "wx/dcmemory.h"
32 #include "wx/button.h"
33 #include "wx/bmpbuttn.h"
36 #include "wx/cursor.h"
37 #include "wx/dialog.h"
38 #include "wx/settings.h"
39 #include "wx/msgdlg.h"
40 #include "wx/choice.h"
41 #include "wx/stattext.h"
42 #include "wx/scrolwin.h"
43 #include "wx/dirdlg.h"
44 #include "wx/combobox.h"
45 #include "wx/layout.h"
47 #include "wx/textdlg.h"
48 #include "wx/filedlg.h"
52 #include "wx/filename.h"
54 #include "wx/propgrid/propgrid.h"
56 #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
59 // -----------------------------------------------------------------------
61 // -----------------------------------------------------------------------
63 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty
,wxPGProperty
,
64 wxString
,const wxString
&,TextCtrl
)
66 wxStringProperty::wxStringProperty( const wxString
& label
,
68 const wxString
& value
)
69 : wxPGProperty(label
,name
)
74 void wxStringProperty::OnSetValue()
76 if ( !m_value
.IsNull() && m_value
.GetString() == wxS("<composed>") )
77 SetFlag(wxPG_PROP_COMPOSED_VALUE
);
79 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
82 DoGenerateComposedValue(s
);
87 wxStringProperty::~wxStringProperty() { }
89 wxString
wxStringProperty::ValueToString( wxVariant
& value
,
92 wxString s
= value
.GetString();
94 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
96 // Value stored in m_value is non-editable, non-full value
97 if ( (argFlags
& wxPG_FULL_VALUE
) ||
98 (argFlags
& wxPG_EDITABLE_VALUE
) ||
101 // Calling this under incorrect conditions will fail
102 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
103 "Sorry, currently default wxPGProperty::ValueToString() "
104 "implementation only works if value is m_value." );
106 DoGenerateComposedValue(s
, argFlags
);
112 // If string is password and value is for visual purposes,
113 // then return asterisks instead the actual string.
114 if ( (m_flags
& wxPG_PROP_PASSWORD
) && !(argFlags
& (wxPG_FULL_VALUE
|wxPG_EDITABLE_VALUE
)) )
115 return wxString(wxChar('*'), s
.Length());
120 bool wxStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
122 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
123 return wxPGProperty::StringToValue(variant
, text
, argFlags
);
125 if ( variant
!= text
)
134 bool wxStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
136 if ( name
== wxPG_STRING_PASSWORD
)
138 m_flags
&= ~(wxPG_PROP_PASSWORD
);
139 if ( value
.GetLong() ) m_flags
|= wxPG_PROP_PASSWORD
;
146 // -----------------------------------------------------------------------
147 // wxNumericPropertyValidator
148 // -----------------------------------------------------------------------
152 wxNumericPropertyValidator::
153 wxNumericPropertyValidator( NumericType numericType
, int base
)
154 : wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST
)
172 arr
.Add(wxS("a")); arr
.Add(wxS("A"));
173 arr
.Add(wxS("b")); arr
.Add(wxS("B"));
174 arr
.Add(wxS("c")); arr
.Add(wxS("C"));
175 arr
.Add(wxS("d")); arr
.Add(wxS("D"));
176 arr
.Add(wxS("e")); arr
.Add(wxS("E"));
177 arr
.Add(wxS("f")); arr
.Add(wxS("F"));
181 if ( numericType
== Signed
)
186 else if ( numericType
== Float
)
192 // Use locale-specific decimal point
193 arr
.Add(wxString::Format("%g", 1.1)[1]);
199 bool wxNumericPropertyValidator::Validate(wxWindow
* parent
)
201 if ( !wxTextValidator::Validate(parent
) )
204 wxWindow
* wnd
= GetWindow();
205 if ( !wxDynamicCast(wnd
, wxTextCtrl
) )
208 // Do not allow zero-length string
209 wxTextCtrl
* tc
= static_cast<wxTextCtrl
*>(wnd
);
210 wxString text
= tc
->GetValue();
218 #endif // wxUSE_VALIDATORS
220 // -----------------------------------------------------------------------
222 // -----------------------------------------------------------------------
224 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
227 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
228 long value
) : wxPGProperty(label
,name
)
233 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
234 const wxLongLong
& value
) : wxPGProperty(label
,name
)
236 SetValue(WXVARIANT(value
));
239 wxIntProperty::~wxIntProperty() { }
241 wxString
wxIntProperty::ValueToString( wxVariant
& value
,
242 int WXUNUSED(argFlags
) ) const
244 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
246 return wxString::Format(wxS("%li"),value
.GetLong());
248 else if ( value
.GetType() == wxPG_VARIANT_TYPE_LONGLONG
)
250 wxLongLong ll
= value
.GetLongLong();
251 return ll
.ToString();
254 return wxEmptyString
;
257 bool wxIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
268 // We know it is a number, but let's still check
270 if ( text
.IsNumber() )
272 // Remove leading zeroes, so that the number is not interpreted as octal
273 wxString::const_iterator i
= text
.begin();
274 wxString::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
276 int firstNonZeroPos
= 0;
278 for ( ; i
!= iMax
; ++i
)
281 if ( c
!= wxS('0') && c
!= wxS(' ') )
286 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
288 wxString variantType
= variant
.GetType();
289 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
291 wxLongLong_t value64
= 0;
293 if ( useText
.ToLongLong(&value64
, 10) &&
294 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
297 bool doChangeValue
= isPrevLong
;
299 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_LONGLONG
)
301 wxLongLong oldValue
= variant
.GetLongLong();
302 if ( oldValue
.GetValue() != value64
)
303 doChangeValue
= true;
308 wxLongLong
ll(value64
);
314 if ( useText
.ToLong( &value32
, 0 ) )
316 if ( !isPrevLong
|| variant
!= value32
)
323 else if ( argFlags
& wxPG_REPORT_ERROR
)
329 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
331 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
!= (long)value
)
333 variant
= (long)value
;
340 // Common validation code to be called in ValidateValue()
343 // Note that 'value' is reference on purpose, so we can write
344 // back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE.
347 bool NumericValidation( const wxPGProperty
* property
,
349 wxPGValidationInfo
* pValidationInfo
,
351 const wxString
& strFmt
)
353 T min
= (T
) wxINT64_MIN
;
354 T max
= (T
) wxINT64_MAX
;
359 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
360 if ( !variant
.IsNull() )
362 variant
.Convert(&min
);
366 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
367 if ( !variant
.IsNull() )
369 variant
.Convert(&max
);
377 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
380 wxString smin
= wxString::Format(strFmt
, min
);
381 wxString smax
= wxString::Format(strFmt
, max
);
383 msg
= wxString::Format(
384 _("Value must be %s or higher."),
387 msg
= wxString::Format(
388 _("Value must be between %s and %s."),
389 smin
.c_str(), smax
.c_str());
390 pValidationInfo
->SetFailureMessage(msg
);
392 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
395 value
= max
- (min
- value
);
404 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
407 wxString smin
= wxString::Format(strFmt
, min
);
408 wxString smax
= wxString::Format(strFmt
, max
);
410 msg
= wxString::Format(
411 _("Value must be %s or less."),
414 msg
= wxString::Format(
415 _("Value must be between %s and %s."),
416 smin
.c_str(), smax
.c_str());
417 pValidationInfo
->SetFailureMessage(msg
);
419 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
422 value
= min
+ (value
- max
);
429 bool wxIntProperty::DoValidation( const wxPGProperty
* property
,
431 wxPGValidationInfo
* pValidationInfo
,
434 return NumericValidation
<wxLongLong_t
>(property
,
441 bool wxIntProperty::ValidateValue( wxVariant
& value
,
442 wxPGValidationInfo
& validationInfo
) const
444 wxLongLong_t ll
= value
.GetLongLong().GetValue();
445 return DoValidation(this, ll
, &validationInfo
,
446 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
449 wxValidator
* wxIntProperty::GetClassValidator()
452 WX_PG_DOGETVALIDATOR_ENTRY()
454 wxValidator
* validator
= new wxNumericPropertyValidator(
455 wxNumericPropertyValidator::Signed
);
457 WX_PG_DOGETVALIDATOR_EXIT(validator
)
463 wxValidator
* wxIntProperty::DoGetValidator() const
465 return GetClassValidator();
468 // -----------------------------------------------------------------------
470 // -----------------------------------------------------------------------
473 #define wxPG_UINT_TEMPLATE_MAX 8
475 static const wxChar
* const gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
476 wxT("%lx"),wxT("0x%lx"),wxT("$%lx"),
477 wxT("%lX"),wxT("0x%lX"),wxT("$%lX"),
478 wxT("%lu"),wxT("%lo")
481 static const char* const gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
482 "%" wxLongLongFmtSpec
"x",
483 "0x%" wxLongLongFmtSpec
"x",
484 "$%" wxLongLongFmtSpec
"x",
485 "%" wxLongLongFmtSpec
"X",
486 "0x%" wxLongLongFmtSpec
"X",
487 "$%" wxLongLongFmtSpec
"X",
488 "%" wxLongLongFmtSpec
"u",
489 "%" wxLongLongFmtSpec
"o"
492 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
493 long,unsigned long,TextCtrl
)
495 void wxUIntProperty::Init()
497 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
499 m_prefix
= wxPG_PREFIX_NONE
;
502 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
503 unsigned long value
) : wxPGProperty(label
,name
)
506 SetValue((long)value
);
509 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
510 const wxULongLong
& value
) : wxPGProperty(label
,name
)
513 SetValue(WXVARIANT(value
));
516 wxUIntProperty::~wxUIntProperty() { }
518 wxString
wxUIntProperty::ValueToString( wxVariant
& value
,
519 int WXUNUSED(argFlags
) ) const
521 size_t index
= m_base
+ m_prefix
;
522 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
523 index
= wxPG_BASE_DEC
;
525 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
527 return wxString::Format(gs_uintTemplates32
[index
],
528 (unsigned long)value
.GetLong());
531 wxULongLong ull
= value
.GetULongLong();
533 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
536 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
538 wxString variantType
= variant
.GetType();
539 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
548 if ( text
[0] == wxS('$') )
551 wxULongLong_t value64
= 0;
552 wxString s
= text
.substr(start
, text
.length() - start
);
554 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
556 if ( value64
>= LONG_MAX
)
558 bool doChangeValue
= isPrevLong
;
560 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_ULONGLONG
)
562 wxULongLong oldValue
= variant
.GetULongLong();
563 if ( oldValue
.GetValue() != value64
)
564 doChangeValue
= true;
569 variant
= wxULongLong(value64
);
575 unsigned long value32
= wxLongLong(value64
).GetLo();
576 if ( !isPrevLong
|| m_value
!= (long)value32
)
578 variant
= (long)value32
;
587 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
589 if ( variant
!= (long)number
)
591 variant
= (long)number
;
597 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
599 wxULongLong_t uul
= value
.GetULongLong().GetValue();
601 NumericValidation
<wxULongLong_t
>(this,
604 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
,
608 wxValidator
* wxUIntProperty::DoGetValidator() const
611 WX_PG_DOGETVALIDATOR_ENTRY()
613 wxValidator
* validator
= new wxNumericPropertyValidator(
614 wxNumericPropertyValidator::Unsigned
,
617 WX_PG_DOGETVALIDATOR_EXIT(validator
)
623 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
625 if ( name
== wxPG_UINT_BASE
)
627 int val
= value
.GetLong();
629 m_realBase
= (wxByte
) val
;
630 if ( m_realBase
> 16 )
634 // Translate logical base to a template array index
636 if ( val
== wxPG_BASE_HEX
)
638 else if ( val
== wxPG_BASE_DEC
)
640 else if ( val
== wxPG_BASE_HEXL
)
644 else if ( name
== wxPG_UINT_PREFIX
)
646 m_prefix
= (wxByte
) value
.GetLong();
652 // -----------------------------------------------------------------------
654 // -----------------------------------------------------------------------
656 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
657 double,double,TextCtrl
)
659 wxFloatProperty::wxFloatProperty( const wxString
& label
,
660 const wxString
& name
,
662 : wxPGProperty(label
,name
)
668 wxFloatProperty::~wxFloatProperty() { }
670 // This helper method provides standard way for floating point-using
671 // properties to convert values to string.
672 const wxString
& wxPropertyGrid::DoubleToString(wxString
& target
,
676 wxString
* precTemplate
)
678 if ( precision
>= 0 )
682 precTemplate
= &text1
;
684 if ( precTemplate
->empty() )
686 *precTemplate
= wxS("%.");
687 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
688 *precTemplate
<< wxS('f');
691 target
.Printf( precTemplate
->c_str(), value
);
695 target
.Printf( wxS("%f"), value
);
698 if ( removeZeroes
&& precision
!= 0 && !target
.empty() )
700 // Remove excess zeroes (do not remove this code just yet,
701 // since sprintf can't do the same consistently across platforms).
702 wxString::const_iterator i
= target
.end() - 1;
703 size_t new_len
= target
.length() - 1;
705 for ( ; i
!= target
.begin(); --i
)
707 if ( *i
!= wxS('0') )
712 wxChar cur_char
= *i
;
713 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
716 if ( new_len
!= target
.length() )
717 target
.resize(new_len
);
720 // Remove sign from zero
721 if ( target
.length() >= 2 && target
[0] == wxS('-') )
724 wxString::const_iterator i
= target
.begin() + 1;
726 for ( ; i
!= target
.end(); i
++ )
728 if ( *i
!= wxS('0') && *i
!= wxS('.') && *i
!= wxS(',') )
736 target
.erase(target
.begin());
742 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
746 if ( !value
.IsNull() )
748 wxPropertyGrid::DoubleToString(text
,
751 !(argFlags
& wxPG_FULL_VALUE
),
757 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
768 bool res
= text
.ToDouble(&value
);
771 if ( variant
!= value
)
777 else if ( argFlags
& wxPG_REPORT_ERROR
)
783 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
785 wxPGValidationInfo
* pValidationInfo
,
788 return NumericValidation
<double>(property
,
796 wxFloatProperty::ValidateValue( wxVariant
& value
,
797 wxPGValidationInfo
& validationInfo
) const
799 double fpv
= value
.GetDouble();
800 return DoValidation(this, fpv
, &validationInfo
,
801 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
804 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
806 if ( name
== wxPG_FLOAT_PRECISION
)
808 m_precision
= value
.GetLong();
815 wxFloatProperty::GetClassValidator()
818 WX_PG_DOGETVALIDATOR_ENTRY()
820 wxValidator
* validator
= new wxNumericPropertyValidator(
821 wxNumericPropertyValidator::Float
);
823 WX_PG_DOGETVALIDATOR_EXIT(validator
)
829 wxValidator
* wxFloatProperty::DoGetValidator() const
831 return GetClassValidator();
834 // -----------------------------------------------------------------------
836 // -----------------------------------------------------------------------
838 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
839 // there is a custom GetEditorClass.
841 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
843 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
845 // Select correct editor control.
846 #if wxPG_INCLUDE_CHECKBOX
847 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
848 return wxPGEditor_Choice
;
849 return wxPGEditor_CheckBox
;
851 return wxPGEditor_Choice
;
855 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
856 wxPGProperty(label
,name
)
858 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
860 SetValue(wxPGVariant_Bool(value
));
862 m_flags
|= wxPG_PROP_USE_DCC
;
865 wxBoolProperty::~wxBoolProperty() { }
867 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
870 bool boolValue
= value
.GetBool();
872 // As a fragment of composite string value,
873 // make it a little more readable.
874 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
882 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
883 return wxEmptyString
;
886 if ( wxPGGlobalVars
->m_autoGetTranslation
)
887 notFmt
= _("Not %s");
889 notFmt
= wxS("Not %s");
891 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
895 if ( !(argFlags
& wxPG_FULL_VALUE
) )
897 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
902 if ( boolValue
) text
= wxS("true");
903 else text
= wxS("false");
908 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
910 bool boolValue
= false;
911 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
912 text
.CmpNoCase(wxS("true")) == 0 ||
913 text
.CmpNoCase(m_label
) == 0 )
922 if ( variant
!= boolValue
)
924 variant
= wxPGVariant_Bool(boolValue
);
930 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
932 bool boolValue
= value
? true : false;
934 if ( variant
!= boolValue
)
936 variant
= wxPGVariant_Bool(boolValue
);
942 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
944 #if wxPG_INCLUDE_CHECKBOX
945 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
947 if ( value
.GetLong() )
948 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
950 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
954 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
956 if ( value
.GetLong() )
957 m_flags
|= wxPG_PROP_USE_DCC
;
959 m_flags
&= ~(wxPG_PROP_USE_DCC
);
965 // -----------------------------------------------------------------------
967 // -----------------------------------------------------------------------
969 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
971 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
973 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
974 const long* values
, int value
) : wxPGProperty(label
,name
)
980 m_choices
.Add(labels
,values
);
982 if ( GetItemCount() )
983 SetValue( (long)value
);
987 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
988 const long* values
, wxPGChoices
* choicesCache
, int value
)
989 : wxPGProperty(label
,name
)
993 wxASSERT( choicesCache
);
995 if ( choicesCache
->IsOk() )
997 m_choices
.Assign( *choicesCache
);
998 m_value
= wxPGVariant_Zero
;
1002 m_choices
.Add(labels
,values
);
1004 if ( GetItemCount() )
1005 SetValue( (long)value
);
1009 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1010 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1011 : wxPGProperty(label
,name
)
1015 if ( &labels
&& labels
.size() )
1017 m_choices
.Set(labels
, values
);
1019 if ( GetItemCount() )
1020 SetValue( (long)value
);
1024 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1025 wxPGChoices
& choices
, int value
)
1026 : wxPGProperty(label
,name
)
1028 m_choices
.Assign( choices
);
1030 if ( GetItemCount() )
1031 SetValue( (long)value
);
1034 int wxEnumProperty::GetIndexForValue( int value
) const
1036 if ( !m_choices
.IsOk() )
1039 int intVal
= m_choices
.Index(value
);
1046 wxEnumProperty::~wxEnumProperty ()
1050 int wxEnumProperty::ms_nextIndex
= -2;
1052 void wxEnumProperty::OnSetValue()
1054 wxString variantType
= m_value
.GetType();
1056 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
1058 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
1060 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
1062 ValueFromString_( m_value
, m_value
.GetString(), 0 );
1069 if ( ms_nextIndex
!= -2 )
1071 m_index
= ms_nextIndex
;
1076 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
1078 // Make sure string value is in the list,
1079 // unless property has string as preferred value type
1080 // To reduce code size, use conversion here as well
1081 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
1082 !wxDynamicCastThis(wxEditEnumProperty
) )
1083 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
1088 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
1089 int WXUNUSED(argFlags
) ) const
1091 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
1092 return value
.GetString();
1094 int index
= m_choices
.Index(value
.GetLong());
1096 return wxEmptyString
;
1098 return m_choices
.GetLabel(index
);
1101 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1103 return ValueFromString_( variant
, text
, argFlags
);
1106 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
1108 return ValueFromInt_( variant
, intVal
, argFlags
);
1111 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
1116 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
1118 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
1119 if ( text
.CmpNoCase(entryLabel
) == 0 )
1122 useValue
= m_choices
.GetValue(i
);
1127 bool asText
= false;
1129 bool isEdit
= this->IsKindOf(wxCLASSINFO(wxEditEnumProperty
));
1131 // If text not any of the choices, store as text instead
1132 // (but only if we are wxEditEnumProperty)
1133 if ( useIndex
== -1 && isEdit
)
1138 int setAsNextIndex
= -2;
1142 setAsNextIndex
= -1;
1145 else if ( useIndex
!= GetIndex() )
1147 if ( useIndex
!= -1 )
1149 setAsNextIndex
= useIndex
;
1150 value
= (long)useValue
;
1154 setAsNextIndex
= -1;
1155 value
= wxPGVariant_MinusOne
;
1159 if ( setAsNextIndex
!= -2 )
1161 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1162 // validation purposes only, and index must not be changed
1163 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1164 ms_nextIndex
= setAsNextIndex
;
1166 if ( isEdit
|| setAsNextIndex
!= -1 )
1174 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1176 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1180 if ( argFlags
& wxPG_FULL_VALUE
)
1182 ms_nextIndex
= GetIndexForValue( intVal
);
1186 if ( intVal
!= GetIndex() )
1188 ms_nextIndex
= intVal
;
1192 if ( ms_nextIndex
!= -2 )
1194 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1195 intVal
= m_choices
.GetValue(intVal
);
1197 variant
= (long)intVal
;
1206 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1212 void wxEnumProperty::SetIndex( int index
)
1218 int wxEnumProperty::GetIndex() const
1220 if ( m_value
.IsNull() )
1223 if ( ms_nextIndex
!= -2 )
1224 return ms_nextIndex
;
1229 // -----------------------------------------------------------------------
1230 // wxEditEnumProperty
1231 // -----------------------------------------------------------------------
1233 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1235 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1237 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1238 const long* values
, const wxString
& value
)
1239 : wxEnumProperty(label
,name
,labels
,values
,0)
1244 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1245 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1246 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1251 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1252 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1253 : wxEnumProperty(label
,name
,labels
,values
,0)
1258 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1259 wxPGChoices
& choices
, const wxString
& value
)
1260 : wxEnumProperty(label
,name
,choices
,0)
1265 wxEditEnumProperty::~wxEditEnumProperty()
1269 // -----------------------------------------------------------------------
1271 // -----------------------------------------------------------------------
1273 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1275 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1277 void wxFlagsProperty::Init()
1279 long value
= m_value
;
1282 // Generate children
1286 unsigned int prevChildCount
= m_children
.size();
1289 if ( prevChildCount
)
1291 wxPropertyGridPageState
* state
= GetParentState();
1293 // State safety check (it may be NULL in immediate parent)
1298 wxPGProperty
* selected
= state
->GetSelection();
1301 if ( selected
->GetParent() == this )
1302 oldSel
= selected
->GetIndexInParent();
1303 else if ( selected
== this )
1307 state
->DoClearSelection();
1310 // Delete old children
1311 for ( i
=0; i
<prevChildCount
; i
++ )
1312 delete m_children
[i
];
1316 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1317 // to child bool property controls.
1318 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1319 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1322 if ( m_choices
.IsOk() )
1324 const wxPGChoices
& choices
= m_choices
;
1326 for ( i
=0; i
<GetItemCount(); i
++ )
1329 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1331 wxPGProperty
* boolProp
;
1332 wxString label
= GetLabel(i
);
1335 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1337 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1342 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1344 if ( attrUseCheckBox
)
1345 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1348 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1350 AddPrivateChild(boolProp
);
1353 m_oldChoicesData
= m_choices
.GetDataPtr();
1356 m_oldValue
= m_value
;
1358 if ( prevChildCount
)
1359 SubPropsChanged(oldSel
);
1362 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1363 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1365 m_oldChoicesData
= NULL
;
1369 m_choices
.Set(labels
,values
);
1371 wxASSERT( GetItemCount() );
1377 m_value
= wxPGVariant_Zero
;
1381 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1382 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1383 : wxPGProperty(label
,name
)
1385 m_oldChoicesData
= NULL
;
1387 if ( &labels
&& labels
.size() )
1389 m_choices
.Set(labels
,values
);
1391 wxASSERT( GetItemCount() );
1393 SetValue( (long)value
);
1397 m_value
= wxPGVariant_Zero
;
1401 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1402 wxPGChoices
& choices
, long value
)
1403 : wxPGProperty(label
,name
)
1405 m_oldChoicesData
= NULL
;
1407 if ( choices
.IsOk() )
1409 m_choices
.Assign(choices
);
1411 wxASSERT( GetItemCount() );
1417 m_value
= wxPGVariant_Zero
;
1421 wxFlagsProperty::~wxFlagsProperty()
1425 void wxFlagsProperty::OnSetValue()
1427 if ( !m_choices
.IsOk() || !GetItemCount() )
1429 m_value
= wxPGVariant_Zero
;
1433 long val
= m_value
.GetLong();
1437 // normalize the value (i.e. remove extra flags)
1439 const wxPGChoices
& choices
= m_choices
;
1440 for ( i
= 0; i
< GetItemCount(); i
++ )
1442 fullFlags
|= choices
.GetValue(i
);
1449 // Need to (re)init now?
1450 if ( GetChildCount() != GetItemCount() ||
1451 m_choices
.GetDataPtr() != m_oldChoicesData
)
1457 long newFlags
= m_value
;
1459 if ( newFlags
!= m_oldValue
)
1461 // Set child modified states
1463 const wxPGChoices
& choices
= m_choices
;
1464 for ( i
= 0; i
<GetItemCount(); i
++ )
1468 flag
= choices
.GetValue(i
);
1470 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1471 Item(i
)->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1474 m_oldValue
= newFlags
;
1478 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1479 int WXUNUSED(argFlags
) ) const
1483 if ( !m_choices
.IsOk() )
1488 const wxPGChoices
& choices
= m_choices
;
1490 for ( i
= 0; i
< GetItemCount(); i
++ )
1493 doAdd
= ( (flags
& choices
.GetValue(i
)) == choices
.GetValue(i
) );
1497 text
+= choices
.GetLabel(i
);
1502 // remove last comma
1503 if ( text
.Len() > 1 )
1504 text
.Truncate ( text
.Len() - 2 );
1509 // Translate string into flag tokens
1510 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1512 if ( !m_choices
.IsOk() )
1517 // semicolons are no longer valid delimeters
1518 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1520 if ( !token
.empty() )
1522 // Determine which one it is
1523 long bit
= IdToBit( token
);
1536 WX_PG_TOKENIZER1_END()
1538 if ( variant
!= (long)newFlags
)
1540 variant
= (long)newFlags
;
1547 // Converts string id to a relevant bit.
1548 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1551 for ( i
= 0; i
< GetItemCount(); i
++ )
1553 if ( id
== GetLabel(i
) )
1555 return m_choices
.GetValue(i
);
1561 void wxFlagsProperty::RefreshChildren()
1563 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1565 int flags
= m_value
.GetLong();
1567 const wxPGChoices
& choices
= m_choices
;
1569 for ( i
= 0; i
< GetItemCount(); i
++ )
1573 flag
= choices
.GetValue(i
);
1575 long subVal
= flags
& flag
;
1576 wxPGProperty
* p
= Item(i
);
1578 if ( subVal
!= (m_oldValue
& flag
) )
1579 p
->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1581 p
->SetValue( subVal
== flag
?true:false );
1587 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1589 wxVariant
& childValue
) const
1591 long oldValue
= thisValue
.GetLong();
1592 long val
= childValue
.GetLong();
1593 unsigned long vi
= m_choices
.GetValue(childIndex
);
1596 return (long) (oldValue
| vi
);
1598 return (long) (oldValue
& ~(vi
));
1601 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1603 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1604 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1606 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1608 Item(i
)->SetAttribute(name
, value
);
1610 // Must return false so that the attribute is stored in
1611 // flag property's actual property storage
1617 // -----------------------------------------------------------------------
1619 // -----------------------------------------------------------------------
1621 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1623 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1624 : wxLongStringProperty(name
,label
,value
)
1626 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1629 wxDirProperty::~wxDirProperty() { }
1631 wxValidator
* wxDirProperty::DoGetValidator() const
1633 return wxFileProperty::GetClassValidator();
1636 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1638 // Update property value from editor, if necessary
1639 wxSize
dlg_sz(300,400);
1641 wxString
dlgMessage(m_dlgMessage
);
1642 if ( dlgMessage
.empty() )
1643 dlgMessage
= _("Choose a directory:");
1644 wxDirDialog
dlg( propGrid
,
1648 #if !wxPG_SMALL_SCREEN
1649 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1657 if ( dlg
.ShowModal() == wxID_OK
)
1659 value
= dlg
.GetPath();
1665 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1667 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1669 m_dlgMessage
= value
.GetString();
1675 // -----------------------------------------------------------------------
1676 // wxPGFileDialogAdapter
1677 // -----------------------------------------------------------------------
1679 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1681 wxFileProperty
* fileProp
= NULL
;
1685 if ( wxDynamicCast(property
, wxFileProperty
) )
1687 fileProp
= ((wxFileProperty
*)property
);
1688 wxFileName filename
= fileProp
->GetValue().GetString();
1689 path
= filename
.GetPath();
1690 indFilter
= fileProp
->m_indFilter
;
1692 if ( path
.empty() && !fileProp
->m_basePath
.empty() )
1693 path
= fileProp
->m_basePath
;
1697 wxFileName
fn(property
->GetValue().GetString());
1698 path
= fn
.GetPath();
1701 wxFileDialog
dlg( propGrid
->GetPanel(),
1702 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1703 property
->GetAttribute(wxS("InitialPath"), path
),
1705 property
->GetAttribute(wxPG_FILE_WILDCARD
, wxALL_FILES
),
1706 property
->GetAttributeAsLong(wxPG_FILE_DIALOG_STYLE
, 0),
1707 wxDefaultPosition
);
1709 if ( indFilter
>= 0 )
1710 dlg
.SetFilterIndex( indFilter
);
1712 if ( dlg
.ShowModal() == wxID_OK
)
1715 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1716 SetValue( dlg
.GetPath() );
1722 // -----------------------------------------------------------------------
1724 // -----------------------------------------------------------------------
1726 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1727 wxString
,const wxString
&,TextCtrlAndButton
)
1729 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1730 const wxString
& value
) : wxPGProperty(label
,name
)
1732 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1734 SetAttribute( wxPG_FILE_WILDCARD
, wxALL_FILES
);
1739 wxFileProperty::~wxFileProperty() {}
1741 wxValidator
* wxFileProperty::GetClassValidator()
1743 #if wxUSE_VALIDATORS
1744 WX_PG_DOGETVALIDATOR_ENTRY()
1746 // Atleast wxPython 2.6.2.1 required that the string argument is given
1748 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1750 wxArrayString exChars
;
1751 exChars
.Add(wxS("?"));
1752 exChars
.Add(wxS("*"));
1753 exChars
.Add(wxS("|"));
1754 exChars
.Add(wxS("<"));
1755 exChars
.Add(wxS(">"));
1756 exChars
.Add(wxS("\""));
1758 validator
->SetExcludes(exChars
);
1760 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1766 wxValidator
* wxFileProperty::DoGetValidator() const
1768 return GetClassValidator();
1771 void wxFileProperty::OnSetValue()
1773 const wxString
& fnstr
= m_value
.GetString();
1775 wxFileName filename
= fnstr
;
1777 if ( !filename
.HasName() )
1779 m_value
= wxPGVariant_EmptyString
;
1782 // Find index for extension.
1783 if ( m_indFilter
< 0 && !fnstr
.empty() )
1785 wxString ext
= filename
.GetExt();
1788 size_t len
= m_wildcard
.length();
1790 pos
= m_wildcard
.find(wxS("|"), pos
);
1791 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1793 size_t ext_begin
= pos
+ 3;
1795 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1796 if ( pos
== wxString::npos
)
1798 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1800 if ( !found_ext
.empty() )
1802 if ( found_ext
[0] == wxS('*') )
1804 m_indFilter
= curind
;
1807 if ( ext
.CmpNoCase(found_ext
) == 0 )
1809 m_indFilter
= curind
;
1815 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1822 wxFileName
wxFileProperty::GetFileName() const
1824 wxFileName filename
;
1826 if ( !m_value
.IsNull() )
1827 filename
= m_value
.GetString();
1832 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1833 int argFlags
) const
1835 wxFileName filename
= value
.GetString();
1837 if ( !filename
.HasName() )
1838 return wxEmptyString
;
1840 wxString fullName
= filename
.GetFullName();
1841 if ( fullName
.empty() )
1842 return wxEmptyString
;
1844 if ( argFlags
& wxPG_FULL_VALUE
)
1846 return filename
.GetFullPath();
1848 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1850 if ( !m_basePath
.empty() )
1852 wxFileName
fn2(filename
);
1853 fn2
.MakeRelativeTo(m_basePath
);
1854 return fn2
.GetFullPath();
1856 return filename
.GetFullPath();
1859 return filename
.GetFullName();
1862 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1864 return new wxPGFileDialogAdapter();
1867 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1869 wxFileName filename
= variant
.GetString();
1871 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1873 if ( filename
!= text
)
1881 if ( filename
.GetFullName() != text
)
1883 wxFileName fn
= filename
;
1884 fn
.SetFullName(text
);
1885 variant
= fn
.GetFullPath();
1893 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1895 // Return false on some occasions to make sure those attribs will get
1896 // stored in m_attributes.
1897 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1899 if ( value
.GetLong() )
1900 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1902 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1905 else if ( name
== wxPG_FILE_WILDCARD
)
1907 m_wildcard
= value
.GetString();
1909 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1911 m_basePath
= value
.GetString();
1913 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1914 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1916 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1918 m_initialPath
= value
.GetString();
1921 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1923 m_dlgTitle
= value
.GetString();
1929 // -----------------------------------------------------------------------
1930 // wxPGLongStringDialogAdapter
1931 // -----------------------------------------------------------------------
1933 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1935 wxString val1
= property
->GetValueAsString(0);
1936 wxString val_orig
= val1
;
1939 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1940 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1942 value
= wxString(val1
);
1944 // Run editor dialog.
1945 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1947 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1948 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1952 if ( val1
!= val_orig
)
1961 // -----------------------------------------------------------------------
1962 // wxLongStringProperty
1963 // -----------------------------------------------------------------------
1965 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1966 wxString
,const wxString
&,TextCtrlAndButton
)
1968 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1969 const wxString
& value
) : wxPGProperty(label
,name
)
1974 wxLongStringProperty::~wxLongStringProperty() {}
1976 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1977 int WXUNUSED(argFlags
) ) const
1982 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1985 if ( propGrid
->IsMainButtonEvent(event
) )
1988 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1990 wxString val1
= useValue
.GetString();
1991 wxString val_orig
= val1
;
1994 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1995 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1997 value
= wxString(val1
);
1999 // Run editor dialog.
2000 if ( OnButtonClick(propGrid
,value
) )
2002 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
2003 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
2007 if ( val1
!= val_orig
)
2009 SetValueInEvent( val1
);
2017 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
2019 return DisplayEditorDialog(this, propGrid
, value
);
2022 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
2025 // launch editor dialog
2026 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
2027 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
2029 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
2031 // Multi-line text editor dialog.
2032 #if !wxPG_SMALL_SCREEN
2033 const int spacing
= 8;
2035 const int spacing
= 4;
2037 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2038 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2039 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
2040 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
2042 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
2043 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
2045 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2046 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
2047 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
2048 buttonSizer
->Realize();
2049 topsizer
->Add( buttonSizer
, 0,
2050 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
2053 dlg
->SetSizer( topsizer
);
2054 topsizer
->SetSizeHints( dlg
);
2056 #if !wxPG_SMALL_SCREEN
2057 dlg
->SetSize(400,300);
2059 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
2062 int res
= dlg
->ShowModal();
2064 if ( res
== wxID_OK
)
2066 value
= ed
->GetValue();
2074 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2076 if ( variant
!= text
)
2084 #if wxUSE_EDITABLELISTBOX
2086 // -----------------------------------------------------------------------
2087 // wxPGArrayEditorDialog
2088 // -----------------------------------------------------------------------
2090 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog
, wxDialog
)
2091 EVT_IDLE(wxPGArrayEditorDialog::OnIdle
)
2094 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog
, wxDialog
)
2096 #include "wx/editlbox.h"
2097 #include "wx/listctrl.h"
2099 // -----------------------------------------------------------------------
2101 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2103 // Repair focus - wxEditableListBox has bitmap buttons, which
2104 // get focus, and lose focus (into the oblivion) when they
2105 // become disabled due to change in control state.
2107 wxWindow
* lastFocused
= m_lastFocused
;
2108 wxWindow
* focus
= ::wxWindow::FindFocus();
2110 // If last focused control became disabled, set focus back to
2111 // wxEditableListBox
2112 if ( lastFocused
&& focus
!= lastFocused
&&
2113 lastFocused
->GetParent() == m_elbSubPanel
&&
2114 !lastFocused
->IsEnabled() )
2116 m_elb
->GetListCtrl()->SetFocus();
2119 m_lastFocused
= focus
;
2124 // -----------------------------------------------------------------------
2126 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2132 // -----------------------------------------------------------------------
2134 void wxPGArrayEditorDialog::Init()
2136 m_lastFocused
= NULL
;
2137 m_hasCustomNewAction
= false;
2138 m_itemPendingAtIndex
= -1;
2141 // -----------------------------------------------------------------------
2143 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow
*parent
,
2144 const wxString
& message
,
2145 const wxString
& caption
,
2152 Create(parent
,message
,caption
,style
,pos
,sz
);
2155 // -----------------------------------------------------------------------
2157 bool wxPGArrayEditorDialog::Create( wxWindow
*parent
,
2158 const wxString
& message
,
2159 const wxString
& caption
,
2164 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2165 // FIXME: This should be only a temporary fix.
2168 int useStyle
= wxCAPTION
;
2170 int useStyle
= style
;
2173 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2175 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2177 #if !wxPG_SMALL_SCREEN
2178 const int spacing
= 4;
2180 const int spacing
= 3;
2185 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2188 if ( !message
.empty() )
2189 topsizer
->Add( new wxStaticText(this,-1,message
),
2190 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2192 m_elb
= new wxEditableListBox(this, wxID_ANY
, message
,
2199 // Populate the list box
2201 for ( unsigned int i
=0; i
<ArrayGetCount(); i
++ )
2202 arr
.push_back(ArrayGet(i
));
2203 m_elb
->SetStrings(arr
);
2205 // Connect event handlers
2207 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2209 but
= m_elb
->GetNewButton();
2210 m_elbSubPanel
= but
->GetParent();
2211 but
->Connect(but
->GetId(), wxEVT_BUTTON
,
2212 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick
),
2215 but
= m_elb
->GetDelButton();
2216 but
->Connect(but
->GetId(), wxEVT_BUTTON
,
2217 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick
),
2220 but
= m_elb
->GetUpButton();
2221 but
->Connect(but
->GetId(), wxEVT_BUTTON
,
2222 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick
),
2225 but
= m_elb
->GetDownButton();
2226 but
->Connect(but
->GetId(), wxEVT_BUTTON
,
2227 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick
),
2230 lc
->Connect(lc
->GetId(), wxEVT_LIST_END_LABEL_EDIT
,
2231 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit
),
2234 topsizer
->Add( m_elb
, 1, wxEXPAND
, spacing
);
2236 // Standard dialog buttons
2237 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2238 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2239 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2240 buttonSizer
->Realize();
2241 topsizer
->Add( buttonSizer
, 0,
2242 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2247 SetSizer( topsizer
);
2248 topsizer
->SetSizeHints( this );
2250 #if !wxPG_SMALL_SCREEN
2251 if ( sz
.x
== wxDefaultSize
.x
&&
2252 sz
.y
== wxDefaultSize
.y
)
2253 SetSize( wxSize(275,360) );
2261 // -----------------------------------------------------------------------
2263 int wxPGArrayEditorDialog::GetSelection() const
2265 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2267 int index
= lc
->GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
2274 // -----------------------------------------------------------------------
2276 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent
& event
)
2278 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2279 int newItemIndex
= lc
->GetItemCount() - 1;
2281 if ( m_hasCustomNewAction
)
2284 if ( OnCustomNewAction(&str
) )
2286 if ( ArrayInsert(str
, newItemIndex
) )
2288 lc
->InsertItem(newItemIndex
, str
);
2293 // Do *not* skip the event! We do not want the wxEditableListBox
2298 m_itemPendingAtIndex
= newItemIndex
;
2304 // -----------------------------------------------------------------------
2306 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent
& event
)
2308 int index
= GetSelection();
2311 ArrayRemoveAt( index
);
2318 // -----------------------------------------------------------------------
2320 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent
& event
)
2322 int index
= GetSelection();
2325 ArraySwap(index
-1,index
);
2332 // -----------------------------------------------------------------------
2334 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent
& event
)
2336 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2337 int index
= GetSelection();
2338 int lastStringIndex
= lc
->GetItemCount() - 1;
2339 if ( index
>= 0 && index
< lastStringIndex
)
2341 ArraySwap(index
, index
+1);
2348 // -----------------------------------------------------------------------
2350 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent
& event
)
2352 wxString str
= event
.GetLabel();
2354 if ( m_itemPendingAtIndex
>= 0 )
2357 if ( ArrayInsert(str
, m_itemPendingAtIndex
) )
2363 // Editable list box doesn't really respect Veto(), but
2364 // it recognizes if no text was added, so we simulate
2366 event
.m_item
.SetText(wxEmptyString
);
2367 m_elb
->GetListCtrl()->SetItemText(m_itemPendingAtIndex
,
2375 // Change an existing item
2376 int index
= GetSelection();
2377 wxASSERT( index
!= wxNOT_FOUND
);
2378 if ( ArraySet(index
, str
) )
2387 #endif // wxUSE_EDITABLELISTBOX
2389 // -----------------------------------------------------------------------
2390 // wxPGArrayStringEditorDialog
2391 // -----------------------------------------------------------------------
2393 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2395 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2398 // -----------------------------------------------------------------------
2400 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2402 return m_array
[index
];
2405 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2407 return m_array
.size();
2410 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2415 m_array
.Insert(str
,index
);
2419 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2421 m_array
[index
] = str
;
2425 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2427 m_array
.RemoveAt(index
);
2430 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2432 wxString old_str
= m_array
[first
];
2433 wxString new_str
= m_array
[second
];
2434 m_array
[first
] = new_str
;
2435 m_array
[second
] = old_str
;
2438 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2439 : wxPGArrayEditorDialog()
2444 void wxPGArrayStringEditorDialog::Init()
2446 m_pCallingClass
= NULL
;
2450 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString
* resString
)
2452 return m_pCallingClass
->OnCustomStringEdit(m_parent
, *resString
);
2455 // -----------------------------------------------------------------------
2456 // wxArrayStringProperty
2457 // -----------------------------------------------------------------------
2459 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2460 wxPGProperty
, // Property we inherit from
2461 wxArrayString
, // Value type name
2462 const wxArrayString
&, // Value type, as given in constructor
2463 TextCtrlAndButton
) // Initial editor
2465 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2466 const wxString
& name
,
2467 const wxArrayString
& array
)
2468 : wxPGProperty(label
,name
)
2474 wxArrayStringProperty::~wxArrayStringProperty() { }
2476 void wxArrayStringProperty::OnSetValue()
2478 GenerateValueAsString();
2482 wxArrayStringProperty::ConvertArrayToString(const wxArrayString
& arr
,
2484 const wxUniChar
& delimiter
) const
2486 if ( delimiter
== '"' || delimiter
== '\'' )
2489 ArrayStringToString(*pString
,
2492 Escape
| QuoteStrings
);
2496 // Regular delimiter
2497 ArrayStringToString(*pString
,
2504 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2505 int argFlags
) const
2508 // If this is called from GetValueAsString(), return cached string
2509 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2514 wxArrayString arr
= m_value
.GetArrayString();
2516 ConvertArrayToString(arr
, &s
, m_delimiter
);
2520 // Converts wxArrayString to a string separated by delimeters and spaces.
2521 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2524 wxArrayStringProperty::ArrayStringToString( wxString
& dst
,
2525 const wxArrayString
& src
,
2526 wxUniChar delimiter
, int flags
)
2532 unsigned int itemCount
= src
.size();
2536 if ( flags
& Escape
)
2544 dst
.append( preas
);
2546 wxString
delimStr(delimiter
);
2548 for ( i
= 0; i
< itemCount
; i
++ )
2550 wxString
str( src
.Item(i
) );
2552 // Do some character conversion.
2553 // Converts \ to \\ and $delimiter to \$delimiter
2554 // Useful when quoting.
2555 if ( flags
& Escape
)
2557 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2559 str
.Replace( preas
, pdr
, true );
2564 if ( i
< (itemCount
-1) )
2566 dst
.append( delimStr
);
2567 dst
.append( wxS(" ") );
2568 dst
.append( preas
);
2570 else if ( flags
& QuoteStrings
)
2571 dst
.append( delimStr
);
2575 void wxArrayStringProperty::GenerateValueAsString()
2577 wxArrayString arr
= m_value
.GetArrayString();
2578 ConvertArrayToString(arr
, &m_display
, m_delimiter
);
2581 // Default implementation doesn't do anything.
2582 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2587 wxPGArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2589 return new wxPGArrayStringEditorDialog();
2592 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2593 wxWindow
* WXUNUSED(primaryCtrl
),
2597 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2599 if ( !propGrid
->EditorValidate() )
2602 // Create editor dialog.
2603 wxPGArrayEditorDialog
* dlg
= CreateEditorDialog();
2604 #if wxUSE_VALIDATORS
2605 wxValidator
* validator
= GetValidator();
2606 wxPGInDialogValidator dialogValidator
;
2609 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2612 strEdDlg
->SetCustomButton(cbt
, this);
2614 dlg
->SetDialogValue( useValue
);
2615 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2617 #if !wxPG_SMALL_SCREEN
2618 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2627 int res
= dlg
->ShowModal();
2629 if ( res
== wxID_OK
&& dlg
->IsModified() )
2631 wxVariant value
= dlg
->GetDialogValue();
2632 if ( !value
.IsNull() )
2634 wxArrayString actualValue
= value
.GetArrayString();
2636 ConvertArrayToString(actualValue
, &tempStr
, m_delimiter
);
2637 #if wxUSE_VALIDATORS
2638 if ( dialogValidator
.DoValidate(propGrid
, validator
,
2642 SetValueInEvent( actualValue
);
2659 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2663 if ( propGrid
->IsMainButtonEvent(event
) )
2664 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2668 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
,
2669 const wxString
& text
, int ) const
2673 if ( m_delimiter
== '"' || m_delimiter
== '\'' )
2676 WX_PG_TOKENIZER2_BEGIN(text
, m_delimiter
)
2678 // Need to replace backslashes with empty characters
2679 // (opposite what is done in ConvertArrayToString()).
2680 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2684 WX_PG_TOKENIZER2_END()
2688 // Regular delimiter
2689 WX_PG_TOKENIZER1_BEGIN(text
, m_delimiter
)
2691 WX_PG_TOKENIZER1_END()
2699 bool wxArrayStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
2701 if ( name
== wxPG_ARRAY_DELIMITER
)
2703 m_delimiter
= value
.GetChar();
2704 GenerateValueAsString();
2710 // -----------------------------------------------------------------------
2711 // wxPGInDialogValidator
2712 // -----------------------------------------------------------------------
2714 #if wxUSE_VALIDATORS
2715 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2716 wxValidator
* validator
,
2717 const wxString
& value
)
2722 wxTextCtrl
* tc
= m_textCtrl
;
2727 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2728 wxPoint(30000,30000));
2735 tc
->SetValue(value
);
2737 validator
->SetWindow(tc
);
2738 bool res
= validator
->Validate(propGrid
);
2743 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2744 wxValidator
* WXUNUSED(validator
),
2745 const wxString
& WXUNUSED(value
) )
2751 // -----------------------------------------------------------------------
2753 #endif // wxUSE_PROPGRID