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 void 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
);
718 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
722 if ( !value
.IsNull() )
724 wxPropertyGrid::DoubleToString(text
,
727 !(argFlags
& wxPG_FULL_VALUE
),
733 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
738 if ( text
.length() == 0 )
744 bool res
= text
.ToDouble(&value
);
747 if ( variant
!= value
)
753 else if ( argFlags
& wxPG_REPORT_ERROR
)
759 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
761 wxPGValidationInfo
* pValidationInfo
,
764 return NumericValidation
<double>(property
,
772 wxFloatProperty::ValidateValue( wxVariant
& value
,
773 wxPGValidationInfo
& validationInfo
) const
775 double fpv
= value
.GetDouble();
776 return DoValidation(this, fpv
, &validationInfo
,
777 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
780 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
782 if ( name
== wxPG_FLOAT_PRECISION
)
784 m_precision
= value
.GetLong();
791 wxFloatProperty::GetClassValidator()
794 WX_PG_DOGETVALIDATOR_ENTRY()
796 wxValidator
* validator
= new wxNumericPropertyValidator(
797 wxNumericPropertyValidator::Float
);
799 WX_PG_DOGETVALIDATOR_EXIT(validator
)
805 wxValidator
* wxFloatProperty::DoGetValidator() const
807 return GetClassValidator();
810 // -----------------------------------------------------------------------
812 // -----------------------------------------------------------------------
814 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
815 // there is a custom GetEditorClass.
817 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
819 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
821 // Select correct editor control.
822 #if wxPG_INCLUDE_CHECKBOX
823 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
824 return wxPGEditor_Choice
;
825 return wxPGEditor_CheckBox
;
827 return wxPGEditor_Choice
;
831 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
832 wxPGProperty(label
,name
)
834 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
836 SetValue(wxPGVariant_Bool(value
));
838 m_flags
|= wxPG_PROP_USE_DCC
;
841 wxBoolProperty::~wxBoolProperty() { }
843 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
846 bool boolValue
= value
.GetBool();
848 // As a fragment of composite string value,
849 // make it a little more readable.
850 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
858 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
859 return wxEmptyString
;
862 if ( wxPGGlobalVars
->m_autoGetTranslation
)
863 notFmt
= _("Not %s");
865 notFmt
= wxS("Not %s");
867 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
871 if ( !(argFlags
& wxPG_FULL_VALUE
) )
873 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
878 if ( boolValue
) text
= wxS("true");
879 else text
= wxS("false");
884 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
886 bool boolValue
= false;
887 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
888 text
.CmpNoCase(wxS("true")) == 0 ||
889 text
.CmpNoCase(m_label
) == 0 )
892 if ( text
.length() == 0 )
898 if ( variant
!= boolValue
)
900 variant
= wxPGVariant_Bool(boolValue
);
906 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
908 bool boolValue
= value
? true : false;
910 if ( variant
!= boolValue
)
912 variant
= wxPGVariant_Bool(boolValue
);
918 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
920 #if wxPG_INCLUDE_CHECKBOX
921 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
923 if ( value
.GetLong() )
924 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
926 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
930 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
932 if ( value
.GetLong() )
933 m_flags
|= wxPG_PROP_USE_DCC
;
935 m_flags
&= ~(wxPG_PROP_USE_DCC
);
941 // -----------------------------------------------------------------------
943 // -----------------------------------------------------------------------
945 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
947 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
949 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
950 const long* values
, int value
) : wxPGProperty(label
,name
)
956 m_choices
.Add(labels
,values
);
958 if ( GetItemCount() )
959 SetValue( (long)value
);
963 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
964 const long* values
, wxPGChoices
* choicesCache
, int value
)
965 : wxPGProperty(label
,name
)
969 wxASSERT( choicesCache
);
971 if ( choicesCache
->IsOk() )
973 m_choices
.Assign( *choicesCache
);
974 m_value
= wxPGVariant_Zero
;
978 m_choices
.Add(labels
,values
);
980 if ( GetItemCount() )
981 SetValue( (long)value
);
985 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
986 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
987 : wxPGProperty(label
,name
)
991 if ( &labels
&& labels
.size() )
993 m_choices
.Set(labels
, values
);
995 if ( GetItemCount() )
996 SetValue( (long)value
);
1000 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1001 wxPGChoices
& choices
, int value
)
1002 : wxPGProperty(label
,name
)
1004 m_choices
.Assign( choices
);
1006 if ( GetItemCount() )
1007 SetValue( (long)value
);
1010 int wxEnumProperty::GetIndexForValue( int value
) const
1012 if ( !m_choices
.IsOk() )
1015 int intVal
= m_choices
.Index(value
);
1022 wxEnumProperty::~wxEnumProperty ()
1026 int wxEnumProperty::ms_nextIndex
= -2;
1028 void wxEnumProperty::OnSetValue()
1030 wxString variantType
= m_value
.GetType();
1032 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
1034 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
1036 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
1038 ValueFromString_( m_value
, m_value
.GetString(), 0 );
1045 if ( ms_nextIndex
!= -2 )
1047 m_index
= ms_nextIndex
;
1052 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
1054 // Make sure string value is in the list,
1055 // unless property has string as preferred value type
1056 // To reduce code size, use conversion here as well
1057 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
1058 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
1059 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
1064 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
1065 int WXUNUSED(argFlags
) ) const
1067 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
1068 return value
.GetString();
1070 int index
= m_choices
.Index(value
.GetLong());
1072 return wxEmptyString
;
1074 return m_choices
.GetLabel(index
);
1077 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1079 return ValueFromString_( variant
, text
, argFlags
);
1082 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
1084 return ValueFromInt_( variant
, intVal
, argFlags
);
1087 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
1092 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
1094 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
1095 if ( text
.CmpNoCase(entryLabel
) == 0 )
1098 useValue
= m_choices
.GetValue(i
);
1103 bool asText
= false;
1105 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
1107 // If text not any of the choices, store as text instead
1108 // (but only if we are wxEditEnumProperty)
1109 if ( useIndex
== -1 && isEdit
)
1114 int setAsNextIndex
= -2;
1118 setAsNextIndex
= -1;
1121 else if ( useIndex
!= GetIndex() )
1123 if ( useIndex
!= -1 )
1125 setAsNextIndex
= useIndex
;
1126 value
= (long)useValue
;
1130 setAsNextIndex
= -1;
1131 value
= wxPGVariant_MinusOne
;
1135 if ( setAsNextIndex
!= -2 )
1137 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1138 // validation purposes only, and index must not be changed
1139 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1140 ms_nextIndex
= setAsNextIndex
;
1142 if ( isEdit
|| setAsNextIndex
!= -1 )
1150 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1152 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1156 if ( argFlags
& wxPG_FULL_VALUE
)
1158 ms_nextIndex
= GetIndexForValue( intVal
);
1162 if ( intVal
!= GetIndex() )
1164 ms_nextIndex
= intVal
;
1168 if ( ms_nextIndex
!= -2 )
1170 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1171 intVal
= m_choices
.GetValue(intVal
);
1173 variant
= (long)intVal
;
1182 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1188 void wxEnumProperty::SetIndex( int index
)
1194 int wxEnumProperty::GetIndex() const
1196 if ( m_value
.IsNull() )
1199 if ( ms_nextIndex
!= -2 )
1200 return ms_nextIndex
;
1205 // -----------------------------------------------------------------------
1206 // wxEditEnumProperty
1207 // -----------------------------------------------------------------------
1209 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1211 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1213 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1214 const long* values
, const wxString
& value
)
1215 : wxEnumProperty(label
,name
,labels
,values
,0)
1220 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1221 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1222 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1227 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1228 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1229 : wxEnumProperty(label
,name
,labels
,values
,0)
1234 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1235 wxPGChoices
& choices
, const wxString
& value
)
1236 : wxEnumProperty(label
,name
,choices
,0)
1241 wxEditEnumProperty::~wxEditEnumProperty()
1245 // -----------------------------------------------------------------------
1247 // -----------------------------------------------------------------------
1249 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1251 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1253 void wxFlagsProperty::Init()
1255 long value
= m_value
;
1258 // Generate children
1262 unsigned int prevChildCount
= m_children
.size();
1265 if ( prevChildCount
)
1267 wxPropertyGridPageState
* state
= GetParentState();
1269 // State safety check (it may be NULL in immediate parent)
1274 wxPGProperty
* selected
= state
->GetSelection();
1277 if ( selected
->GetParent() == this )
1278 oldSel
= selected
->GetIndexInParent();
1279 else if ( selected
== this )
1283 state
->DoClearSelection();
1286 // Delete old children
1287 for ( i
=0; i
<prevChildCount
; i
++ )
1288 delete m_children
[i
];
1292 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1293 // to child bool property controls.
1294 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1295 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1298 if ( m_choices
.IsOk() )
1300 const wxPGChoices
& choices
= m_choices
;
1302 for ( i
=0; i
<GetItemCount(); i
++ )
1305 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1307 wxPGProperty
* boolProp
;
1308 wxString label
= GetLabel(i
);
1311 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1313 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1318 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1320 if ( attrUseCheckBox
)
1321 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1324 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1326 AddPrivateChild(boolProp
);
1329 m_oldChoicesData
= m_choices
.GetDataPtr();
1332 m_oldValue
= m_value
;
1334 if ( prevChildCount
)
1335 SubPropsChanged(oldSel
);
1338 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1339 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1341 m_oldChoicesData
= NULL
;
1345 m_choices
.Set(labels
,values
);
1347 wxASSERT( GetItemCount() );
1353 m_value
= wxPGVariant_Zero
;
1357 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1358 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1359 : wxPGProperty(label
,name
)
1361 m_oldChoicesData
= NULL
;
1363 if ( &labels
&& labels
.size() )
1365 m_choices
.Set(labels
,values
);
1367 wxASSERT( GetItemCount() );
1369 SetValue( (long)value
);
1373 m_value
= wxPGVariant_Zero
;
1377 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1378 wxPGChoices
& choices
, long value
)
1379 : wxPGProperty(label
,name
)
1381 m_oldChoicesData
= NULL
;
1383 if ( choices
.IsOk() )
1385 m_choices
.Assign(choices
);
1387 wxASSERT( GetItemCount() );
1393 m_value
= wxPGVariant_Zero
;
1397 wxFlagsProperty::~wxFlagsProperty()
1401 void wxFlagsProperty::OnSetValue()
1403 if ( !m_choices
.IsOk() || !GetItemCount() )
1405 m_value
= wxPGVariant_Zero
;
1409 long val
= m_value
.GetLong();
1413 // normalize the value (i.e. remove extra flags)
1415 const wxPGChoices
& choices
= m_choices
;
1416 for ( i
= 0; i
< GetItemCount(); i
++ )
1418 fullFlags
|= choices
.GetValue(i
);
1425 // Need to (re)init now?
1426 if ( GetChildCount() != GetItemCount() ||
1427 m_choices
.GetDataPtr() != m_oldChoicesData
)
1433 long newFlags
= m_value
;
1435 if ( newFlags
!= m_oldValue
)
1437 // Set child modified states
1439 const wxPGChoices
& choices
= m_choices
;
1440 for ( i
= 0; i
<GetItemCount(); i
++ )
1444 flag
= choices
.GetValue(i
);
1446 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1447 Item(i
)->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1450 m_oldValue
= newFlags
;
1454 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1455 int WXUNUSED(argFlags
) ) const
1459 if ( !m_choices
.IsOk() )
1464 const wxPGChoices
& choices
= m_choices
;
1466 for ( i
= 0; i
< GetItemCount(); i
++ )
1469 doAdd
= ( flags
& choices
.GetValue(i
) );
1473 text
+= choices
.GetLabel(i
);
1478 // remove last comma
1479 if ( text
.Len() > 1 )
1480 text
.Truncate ( text
.Len() - 2 );
1485 // Translate string into flag tokens
1486 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1488 if ( !m_choices
.IsOk() )
1493 // semicolons are no longer valid delimeters
1494 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1496 if ( token
.length() )
1498 // Determine which one it is
1499 long bit
= IdToBit( token
);
1512 WX_PG_TOKENIZER1_END()
1514 if ( variant
!= (long)newFlags
)
1516 variant
= (long)newFlags
;
1523 // Converts string id to a relevant bit.
1524 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1527 for ( i
= 0; i
< GetItemCount(); i
++ )
1529 if ( id
== GetLabel(i
) )
1531 return m_choices
.GetValue(i
);
1537 void wxFlagsProperty::RefreshChildren()
1539 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1541 int flags
= m_value
.GetLong();
1543 const wxPGChoices
& choices
= m_choices
;
1545 for ( i
= 0; i
< GetItemCount(); i
++ )
1549 flag
= choices
.GetValue(i
);
1551 long subVal
= flags
& flag
;
1552 wxPGProperty
* p
= Item(i
);
1554 if ( subVal
!= (m_oldValue
& flag
) )
1555 p
->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1557 p
->SetValue( subVal
?true:false );
1563 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1565 wxVariant
& childValue
) const
1567 long oldValue
= thisValue
.GetLong();
1568 long val
= childValue
.GetLong();
1569 unsigned long vi
= m_choices
.GetValue(childIndex
);
1572 return (long) (oldValue
| vi
);
1574 return (long) (oldValue
& ~(vi
));
1577 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1579 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1580 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1582 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1584 Item(i
)->SetAttribute(name
, value
);
1586 // Must return false so that the attribute is stored in
1587 // flag property's actual property storage
1593 // -----------------------------------------------------------------------
1595 // -----------------------------------------------------------------------
1597 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1599 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1600 : wxLongStringProperty(name
,label
,value
)
1602 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1605 wxDirProperty::~wxDirProperty() { }
1607 wxValidator
* wxDirProperty::DoGetValidator() const
1609 return wxFileProperty::GetClassValidator();
1612 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1614 // Update property value from editor, if necessary
1615 wxSize
dlg_sz(300,400);
1617 wxString
dlgMessage(m_dlgMessage
);
1618 if ( dlgMessage
.empty() )
1619 dlgMessage
= _("Choose a directory:");
1620 wxDirDialog
dlg( propGrid
,
1624 #if !wxPG_SMALL_SCREEN
1625 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1633 if ( dlg
.ShowModal() == wxID_OK
)
1635 value
= dlg
.GetPath();
1641 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1643 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1645 m_dlgMessage
= value
.GetString();
1651 // -----------------------------------------------------------------------
1652 // wxPGFileDialogAdapter
1653 // -----------------------------------------------------------------------
1655 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1657 wxFileProperty
* fileProp
= NULL
;
1661 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1663 fileProp
= ((wxFileProperty
*)property
);
1664 wxFileName filename
= fileProp
->GetValue().GetString();
1665 path
= filename
.GetPath();
1666 indFilter
= fileProp
->m_indFilter
;
1668 if ( !path
.length() && fileProp
->m_basePath
.length() )
1669 path
= fileProp
->m_basePath
;
1673 wxFileName
fn(property
->GetValue().GetString());
1674 path
= fn
.GetPath();
1677 wxFileDialog
dlg( propGrid
->GetPanel(),
1678 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1679 property
->GetAttribute(wxS("InitialPath"), path
),
1681 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1683 wxDefaultPosition
);
1685 if ( indFilter
>= 0 )
1686 dlg
.SetFilterIndex( indFilter
);
1688 if ( dlg
.ShowModal() == wxID_OK
)
1691 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1692 SetValue( dlg
.GetPath() );
1698 // -----------------------------------------------------------------------
1700 // -----------------------------------------------------------------------
1702 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1703 wxString
,const wxString
&,TextCtrlAndButton
)
1705 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1706 const wxString
& value
) : wxPGProperty(label
,name
)
1708 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1710 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1715 wxFileProperty::~wxFileProperty() {}
1717 wxValidator
* wxFileProperty::GetClassValidator()
1719 #if wxUSE_VALIDATORS
1720 WX_PG_DOGETVALIDATOR_ENTRY()
1722 // Atleast wxPython 2.6.2.1 required that the string argument is given
1724 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1726 wxArrayString exChars
;
1727 exChars
.Add(wxS("?"));
1728 exChars
.Add(wxS("*"));
1729 exChars
.Add(wxS("|"));
1730 exChars
.Add(wxS("<"));
1731 exChars
.Add(wxS(">"));
1732 exChars
.Add(wxS("\""));
1734 validator
->SetExcludes(exChars
);
1736 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1742 wxValidator
* wxFileProperty::DoGetValidator() const
1744 return GetClassValidator();
1747 void wxFileProperty::OnSetValue()
1749 const wxString
& fnstr
= m_value
.GetString();
1751 wxFileName filename
= fnstr
;
1753 if ( !filename
.HasName() )
1755 m_value
= wxPGVariant_EmptyString
;
1758 // Find index for extension.
1759 if ( m_indFilter
< 0 && fnstr
.length() )
1761 wxString ext
= filename
.GetExt();
1764 size_t len
= m_wildcard
.length();
1766 pos
= m_wildcard
.find(wxS("|"), pos
);
1767 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1769 size_t ext_begin
= pos
+ 3;
1771 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1772 if ( pos
== wxString::npos
)
1774 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1776 if ( found_ext
.length() > 0 )
1778 if ( found_ext
[0] == wxS('*') )
1780 m_indFilter
= curind
;
1783 if ( ext
.CmpNoCase(found_ext
) == 0 )
1785 m_indFilter
= curind
;
1791 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1798 wxFileName
wxFileProperty::GetFileName() const
1800 wxFileName filename
;
1802 if ( !m_value
.IsNull() )
1803 filename
= m_value
.GetString();
1808 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1809 int argFlags
) const
1811 wxFileName filename
= value
.GetString();
1813 if ( !filename
.HasName() )
1814 return wxEmptyString
;
1816 wxString fullName
= filename
.GetFullName();
1817 if ( !fullName
.length() )
1818 return wxEmptyString
;
1820 if ( argFlags
& wxPG_FULL_VALUE
)
1822 return filename
.GetFullPath();
1824 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1826 if ( m_basePath
.Length() )
1828 wxFileName
fn2(filename
);
1829 fn2
.MakeRelativeTo(m_basePath
);
1830 return fn2
.GetFullPath();
1832 return filename
.GetFullPath();
1835 return filename
.GetFullName();
1838 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1840 return new wxPGFileDialogAdapter();
1843 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1845 wxFileName filename
= variant
.GetString();
1847 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1849 if ( filename
!= text
)
1857 if ( filename
.GetFullName() != text
)
1859 wxFileName fn
= filename
;
1860 fn
.SetFullName(text
);
1861 variant
= fn
.GetFullPath();
1869 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1871 // Return false on some occasions to make sure those attribs will get
1872 // stored in m_attributes.
1873 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1875 if ( value
.GetLong() )
1876 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1878 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1881 else if ( name
== wxPG_FILE_WILDCARD
)
1883 m_wildcard
= value
.GetString();
1885 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1887 m_basePath
= value
.GetString();
1889 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1890 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1892 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1894 m_initialPath
= value
.GetString();
1897 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1899 m_dlgTitle
= value
.GetString();
1905 // -----------------------------------------------------------------------
1906 // wxPGLongStringDialogAdapter
1907 // -----------------------------------------------------------------------
1909 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1911 wxString val1
= property
->GetValueAsString(0);
1912 wxString val_orig
= val1
;
1915 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1916 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1918 value
= wxString(val1
);
1920 // Run editor dialog.
1921 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1923 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1924 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1928 if ( val1
!= val_orig
)
1937 // -----------------------------------------------------------------------
1938 // wxLongStringProperty
1939 // -----------------------------------------------------------------------
1941 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1942 wxString
,const wxString
&,TextCtrlAndButton
)
1944 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1945 const wxString
& value
) : wxPGProperty(label
,name
)
1950 wxLongStringProperty::~wxLongStringProperty() {}
1952 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1953 int WXUNUSED(argFlags
) ) const
1958 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1961 if ( propGrid
->IsMainButtonEvent(event
) )
1964 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1966 wxString val1
= useValue
.GetString();
1967 wxString val_orig
= val1
;
1970 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1971 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1973 value
= wxString(val1
);
1975 // Run editor dialog.
1976 if ( OnButtonClick(propGrid
,value
) )
1978 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1979 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1983 if ( val1
!= val_orig
)
1985 SetValueInEvent( val1
);
1993 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1995 return DisplayEditorDialog(this, propGrid
, value
);
1998 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
2001 // launch editor dialog
2002 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
2003 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
2005 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
2007 // Multi-line text editor dialog.
2008 #if !wxPG_SMALL_SCREEN
2009 const int spacing
= 8;
2011 const int spacing
= 4;
2013 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2014 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2015 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
2016 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
2018 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
2019 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
2021 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2022 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
2023 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
2024 buttonSizer
->Realize();
2025 topsizer
->Add( buttonSizer
, 0,
2026 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
2029 dlg
->SetSizer( topsizer
);
2030 topsizer
->SetSizeHints( dlg
);
2032 #if !wxPG_SMALL_SCREEN
2033 dlg
->SetSize(400,300);
2035 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
2038 int res
= dlg
->ShowModal();
2040 if ( res
== wxID_OK
)
2042 value
= ed
->GetValue();
2050 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2052 if ( variant
!= text
)
2060 #if wxUSE_EDITABLELISTBOX
2062 // -----------------------------------------------------------------------
2063 // wxPGArrayEditorDialog
2064 // -----------------------------------------------------------------------
2066 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog
, wxDialog
)
2067 EVT_IDLE(wxPGArrayEditorDialog::OnIdle
)
2070 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog
, wxDialog
)
2072 #include "wx/editlbox.h"
2073 #include "wx/listctrl.h"
2075 // -----------------------------------------------------------------------
2077 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2079 // Repair focus - wxEditableListBox has bitmap buttons, which
2080 // get focus, and lose focus (into the oblivion) when they
2081 // become disabled due to change in control state.
2083 wxWindow
* lastFocused
= m_lastFocused
;
2084 wxWindow
* focus
= ::wxWindow::FindFocus();
2086 // If last focused control became disabled, set focus back to
2087 // wxEditableListBox
2088 if ( lastFocused
&& focus
!= lastFocused
&&
2089 lastFocused
->GetParent() == m_elbSubPanel
&&
2090 !lastFocused
->IsEnabled() )
2092 m_elb
->GetListCtrl()->SetFocus();
2095 m_lastFocused
= focus
;
2100 // -----------------------------------------------------------------------
2102 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2108 // -----------------------------------------------------------------------
2110 void wxPGArrayEditorDialog::Init()
2112 m_lastFocused
= NULL
;
2113 m_hasCustomNewAction
= false;
2114 m_itemPendingAtIndex
= -1;
2117 // -----------------------------------------------------------------------
2119 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow
*parent
,
2120 const wxString
& message
,
2121 const wxString
& caption
,
2128 Create(parent
,message
,caption
,style
,pos
,sz
);
2131 // -----------------------------------------------------------------------
2133 bool wxPGArrayEditorDialog::Create( wxWindow
*parent
,
2134 const wxString
& message
,
2135 const wxString
& caption
,
2140 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2141 // FIXME: This should be only a temporary fix.
2144 int useStyle
= wxCAPTION
;
2146 int useStyle
= style
;
2149 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2151 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2153 #if !wxPG_SMALL_SCREEN
2154 const int spacing
= 4;
2156 const int spacing
= 3;
2161 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2164 if ( message
.length() )
2165 topsizer
->Add( new wxStaticText(this,-1,message
),
2166 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2168 m_elb
= new wxEditableListBox(this, wxID_ANY
, message
,
2175 // Populate the list box
2177 for ( unsigned int i
=0; i
<ArrayGetCount(); i
++ )
2178 arr
.push_back(ArrayGet(i
));
2179 m_elb
->SetStrings(arr
);
2181 // Connect event handlers
2183 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2185 but
= m_elb
->GetNewButton();
2186 m_elbSubPanel
= but
->GetParent();
2187 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2188 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick
),
2191 but
= m_elb
->GetDelButton();
2192 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2193 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick
),
2196 but
= m_elb
->GetUpButton();
2197 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2198 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick
),
2201 but
= m_elb
->GetDownButton();
2202 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2203 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick
),
2206 lc
->Connect(lc
->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT
,
2207 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit
),
2210 topsizer
->Add( m_elb
, 1, wxEXPAND
, spacing
);
2212 // Standard dialog buttons
2213 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2214 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2215 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2216 buttonSizer
->Realize();
2217 topsizer
->Add( buttonSizer
, 0,
2218 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2223 SetSizer( topsizer
);
2224 topsizer
->SetSizeHints( this );
2226 #if !wxPG_SMALL_SCREEN
2227 if ( sz
.x
== wxDefaultSize
.x
&&
2228 sz
.y
== wxDefaultSize
.y
)
2229 SetSize( wxSize(275,360) );
2237 // -----------------------------------------------------------------------
2239 int wxPGArrayEditorDialog::GetSelection() const
2241 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2243 int index
= lc
->GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
2250 // -----------------------------------------------------------------------
2252 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent
& event
)
2254 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2255 int newItemIndex
= lc
->GetItemCount() - 1;
2257 if ( m_hasCustomNewAction
)
2260 if ( OnCustomNewAction(&str
) )
2262 if ( ArrayInsert(str
, newItemIndex
) )
2264 lc
->InsertItem(newItemIndex
, str
);
2269 // Do *not* skip the event! We do not want the wxEditableListBox
2274 m_itemPendingAtIndex
= newItemIndex
;
2280 // -----------------------------------------------------------------------
2282 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent
& event
)
2284 int index
= GetSelection();
2287 ArrayRemoveAt( index
);
2294 // -----------------------------------------------------------------------
2296 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent
& event
)
2298 int index
= GetSelection();
2301 ArraySwap(index
-1,index
);
2308 // -----------------------------------------------------------------------
2310 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent
& event
)
2312 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2313 int index
= GetSelection();
2314 int lastStringIndex
= lc
->GetItemCount() - 1;
2315 if ( index
>= 0 && index
< lastStringIndex
)
2317 ArraySwap(index
, index
+1);
2324 // -----------------------------------------------------------------------
2326 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent
& event
)
2328 wxString str
= event
.GetLabel();
2330 if ( m_itemPendingAtIndex
>= 0 )
2333 if ( ArrayInsert(str
, m_itemPendingAtIndex
) )
2339 // Editable list box doesn't really respect Veto(), but
2340 // it recognizes if no text was added, so we simulate
2342 event
.m_item
.SetText(wxEmptyString
);
2343 m_elb
->GetListCtrl()->SetItemText(m_itemPendingAtIndex
,
2351 // Change an existing item
2352 int index
= GetSelection();
2353 wxASSERT( index
!= wxNOT_FOUND
);
2354 if ( ArraySet(index
, str
) )
2363 #endif // wxUSE_EDITABLELISTBOX
2365 // -----------------------------------------------------------------------
2366 // wxPGArrayStringEditorDialog
2367 // -----------------------------------------------------------------------
2369 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2371 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2374 // -----------------------------------------------------------------------
2376 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2378 return m_array
[index
];
2381 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2383 return m_array
.size();
2386 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2391 m_array
.Insert(str
,index
);
2395 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2397 m_array
[index
] = str
;
2401 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2403 m_array
.RemoveAt(index
);
2406 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2408 wxString old_str
= m_array
[first
];
2409 wxString new_str
= m_array
[second
];
2410 m_array
[first
] = new_str
;
2411 m_array
[second
] = old_str
;
2414 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2415 : wxPGArrayEditorDialog()
2420 void wxPGArrayStringEditorDialog::Init()
2422 m_pCallingClass
= NULL
;
2426 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString
* resString
)
2428 return m_pCallingClass
->OnCustomStringEdit(m_parent
, *resString
);
2431 // -----------------------------------------------------------------------
2432 // wxArrayStringProperty
2433 // -----------------------------------------------------------------------
2435 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2436 wxPGProperty
, // Property we inherit from
2437 wxArrayString
, // Value type name
2438 const wxArrayString
&, // Value type, as given in constructor
2439 TextCtrlAndButton
) // Initial editor
2441 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2442 const wxString
& name
,
2443 const wxArrayString
& array
)
2444 : wxPGProperty(label
,name
)
2450 wxArrayStringProperty::~wxArrayStringProperty() { }
2452 void wxArrayStringProperty::OnSetValue()
2454 GenerateValueAsString();
2458 wxArrayStringProperty::ConvertArrayToString(const wxArrayString
& arr
,
2460 const wxUniChar
& delimiter
) const
2462 if ( delimiter
== '"' || delimiter
== '\'' )
2465 ArrayStringToString(*pString
,
2468 Escape
| QuoteStrings
);
2472 // Regular delimiter
2473 ArrayStringToString(*pString
,
2480 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2481 int argFlags
) const
2484 // If this is called from GetValueAsString(), return cached string
2485 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2490 wxArrayString arr
= m_value
.GetArrayString();
2492 ConvertArrayToString(arr
, &s
, m_delimiter
);
2496 // Converts wxArrayString to a string separated by delimeters and spaces.
2497 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2500 wxArrayStringProperty::ArrayStringToString( wxString
& dst
,
2501 const wxArrayString
& src
,
2502 wxUniChar delimiter
, int flags
)
2508 unsigned int itemCount
= src
.size();
2512 if ( flags
& Escape
)
2515 pdr
= wxS("\\") + static_cast<wchar_t>(delimiter
);
2519 dst
.append( preas
);
2521 wxString
delimStr(delimiter
);
2523 for ( i
= 0; i
< itemCount
; i
++ )
2525 wxString
str( src
.Item(i
) );
2527 // Do some character conversion.
2528 // Converts \ to \\ and $delimiter to \$delimiter
2529 // Useful when quoting.
2530 if ( flags
& Escape
)
2532 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2534 str
.Replace( preas
, pdr
, true );
2539 if ( i
< (itemCount
-1) )
2541 dst
.append( delimStr
);
2542 dst
.append( wxS(" ") );
2543 dst
.append( preas
);
2545 else if ( flags
& QuoteStrings
)
2546 dst
.append( delimStr
);
2550 void wxArrayStringProperty::GenerateValueAsString()
2552 wxArrayString arr
= m_value
.GetArrayString();
2553 ConvertArrayToString(arr
, &m_display
, m_delimiter
);
2556 // Default implementation doesn't do anything.
2557 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2562 wxPGArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2564 return new wxPGArrayStringEditorDialog();
2567 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2568 wxWindow
* WXUNUSED(primaryCtrl
),
2572 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2574 if ( !propGrid
->EditorValidate() )
2577 // Create editor dialog.
2578 wxPGArrayEditorDialog
* dlg
= CreateEditorDialog();
2579 #if wxUSE_VALIDATORS
2580 wxValidator
* validator
= GetValidator();
2581 wxPGInDialogValidator dialogValidator
;
2584 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2587 strEdDlg
->SetCustomButton(cbt
, this);
2589 dlg
->SetDialogValue( useValue
);
2590 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2592 #if !wxPG_SMALL_SCREEN
2593 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2602 int res
= dlg
->ShowModal();
2604 if ( res
== wxID_OK
&& dlg
->IsModified() )
2606 wxVariant value
= dlg
->GetDialogValue();
2607 if ( !value
.IsNull() )
2609 wxArrayString actualValue
= value
.GetArrayString();
2611 ConvertArrayToString(actualValue
, &tempStr
, m_delimiter
);
2612 #if wxUSE_VALIDATORS
2613 if ( dialogValidator
.DoValidate(propGrid
, validator
,
2617 SetValueInEvent( actualValue
);
2634 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2638 if ( propGrid
->IsMainButtonEvent(event
) )
2639 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2643 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
,
2644 const wxString
& text
, int ) const
2648 if ( m_delimiter
== '"' || m_delimiter
== '\'' )
2651 WX_PG_TOKENIZER2_BEGIN(text
, m_delimiter
)
2653 // Need to replace backslashes with empty characters
2654 // (opposite what is done in ConvertArrayToString()).
2655 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2659 WX_PG_TOKENIZER2_END()
2663 // Regular delimiter
2664 WX_PG_TOKENIZER1_BEGIN(text
, m_delimiter
)
2666 WX_PG_TOKENIZER1_END()
2674 bool wxArrayStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
2676 if ( name
== wxPG_ARRAY_DELIMITER
)
2678 m_delimiter
= value
.GetChar();
2679 GenerateValueAsString();
2685 // -----------------------------------------------------------------------
2686 // wxPGInDialogValidator
2687 // -----------------------------------------------------------------------
2689 #if wxUSE_VALIDATORS
2690 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2691 wxValidator
* validator
,
2692 const wxString
& value
)
2697 wxTextCtrl
* tc
= m_textCtrl
;
2702 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2703 wxPoint(30000,30000));
2710 tc
->SetValue(value
);
2712 validator
->SetWindow(tc
);
2713 bool res
= validator
->Validate(propGrid
);
2718 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2719 wxValidator
* WXUNUSED(validator
),
2720 const wxString
& WXUNUSED(value
) )
2726 // -----------------------------------------------------------------------
2728 #endif // wxUSE_PROPGRID