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
);
717 // Remove sign from zero
718 if ( target
.length() >= 2 && target
[0] == wxS('-') )
721 wxString::const_iterator i
= target
.begin() + 1;
723 for ( ; i
!= target
.end(); i
++ )
725 if ( *i
!= wxS('0') && *i
!= wxS('.') )
733 target
.erase(target
.begin());
737 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
741 if ( !value
.IsNull() )
743 wxPropertyGrid::DoubleToString(text
,
746 !(argFlags
& wxPG_FULL_VALUE
),
752 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
757 if ( text
.length() == 0 )
763 bool res
= text
.ToDouble(&value
);
766 if ( variant
!= value
)
772 else if ( argFlags
& wxPG_REPORT_ERROR
)
778 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
780 wxPGValidationInfo
* pValidationInfo
,
783 return NumericValidation
<double>(property
,
791 wxFloatProperty::ValidateValue( wxVariant
& value
,
792 wxPGValidationInfo
& validationInfo
) const
794 double fpv
= value
.GetDouble();
795 return DoValidation(this, fpv
, &validationInfo
,
796 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
799 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
801 if ( name
== wxPG_FLOAT_PRECISION
)
803 m_precision
= value
.GetLong();
810 wxFloatProperty::GetClassValidator()
813 WX_PG_DOGETVALIDATOR_ENTRY()
815 wxValidator
* validator
= new wxNumericPropertyValidator(
816 wxNumericPropertyValidator::Float
);
818 WX_PG_DOGETVALIDATOR_EXIT(validator
)
824 wxValidator
* wxFloatProperty::DoGetValidator() const
826 return GetClassValidator();
829 // -----------------------------------------------------------------------
831 // -----------------------------------------------------------------------
833 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
834 // there is a custom GetEditorClass.
836 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
838 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
840 // Select correct editor control.
841 #if wxPG_INCLUDE_CHECKBOX
842 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
843 return wxPGEditor_Choice
;
844 return wxPGEditor_CheckBox
;
846 return wxPGEditor_Choice
;
850 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
851 wxPGProperty(label
,name
)
853 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
855 SetValue(wxPGVariant_Bool(value
));
857 m_flags
|= wxPG_PROP_USE_DCC
;
860 wxBoolProperty::~wxBoolProperty() { }
862 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
865 bool boolValue
= value
.GetBool();
867 // As a fragment of composite string value,
868 // make it a little more readable.
869 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
877 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
878 return wxEmptyString
;
881 if ( wxPGGlobalVars
->m_autoGetTranslation
)
882 notFmt
= _("Not %s");
884 notFmt
= wxS("Not %s");
886 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
890 if ( !(argFlags
& wxPG_FULL_VALUE
) )
892 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
897 if ( boolValue
) text
= wxS("true");
898 else text
= wxS("false");
903 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
905 bool boolValue
= false;
906 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
907 text
.CmpNoCase(wxS("true")) == 0 ||
908 text
.CmpNoCase(m_label
) == 0 )
911 if ( text
.length() == 0 )
917 if ( variant
!= boolValue
)
919 variant
= wxPGVariant_Bool(boolValue
);
925 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
927 bool boolValue
= value
? true : false;
929 if ( variant
!= boolValue
)
931 variant
= wxPGVariant_Bool(boolValue
);
937 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
939 #if wxPG_INCLUDE_CHECKBOX
940 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
942 if ( value
.GetLong() )
943 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
945 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
949 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
951 if ( value
.GetLong() )
952 m_flags
|= wxPG_PROP_USE_DCC
;
954 m_flags
&= ~(wxPG_PROP_USE_DCC
);
960 // -----------------------------------------------------------------------
962 // -----------------------------------------------------------------------
964 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
966 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
968 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
969 const long* values
, int value
) : wxPGProperty(label
,name
)
975 m_choices
.Add(labels
,values
);
977 if ( GetItemCount() )
978 SetValue( (long)value
);
982 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
983 const long* values
, wxPGChoices
* choicesCache
, int value
)
984 : wxPGProperty(label
,name
)
988 wxASSERT( choicesCache
);
990 if ( choicesCache
->IsOk() )
992 m_choices
.Assign( *choicesCache
);
993 m_value
= wxPGVariant_Zero
;
997 m_choices
.Add(labels
,values
);
999 if ( GetItemCount() )
1000 SetValue( (long)value
);
1004 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1005 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1006 : wxPGProperty(label
,name
)
1010 if ( &labels
&& labels
.size() )
1012 m_choices
.Set(labels
, values
);
1014 if ( GetItemCount() )
1015 SetValue( (long)value
);
1019 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
1020 wxPGChoices
& choices
, int value
)
1021 : wxPGProperty(label
,name
)
1023 m_choices
.Assign( choices
);
1025 if ( GetItemCount() )
1026 SetValue( (long)value
);
1029 int wxEnumProperty::GetIndexForValue( int value
) const
1031 if ( !m_choices
.IsOk() )
1034 int intVal
= m_choices
.Index(value
);
1041 wxEnumProperty::~wxEnumProperty ()
1045 int wxEnumProperty::ms_nextIndex
= -2;
1047 void wxEnumProperty::OnSetValue()
1049 wxString variantType
= m_value
.GetType();
1051 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
1053 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
1055 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
1057 ValueFromString_( m_value
, m_value
.GetString(), 0 );
1064 if ( ms_nextIndex
!= -2 )
1066 m_index
= ms_nextIndex
;
1071 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
1073 // Make sure string value is in the list,
1074 // unless property has string as preferred value type
1075 // To reduce code size, use conversion here as well
1076 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
1077 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
1078 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
1083 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
1084 int WXUNUSED(argFlags
) ) const
1086 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
1087 return value
.GetString();
1089 int index
= m_choices
.Index(value
.GetLong());
1091 return wxEmptyString
;
1093 return m_choices
.GetLabel(index
);
1096 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1098 return ValueFromString_( variant
, text
, argFlags
);
1101 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
1103 return ValueFromInt_( variant
, intVal
, argFlags
);
1106 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
1111 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
1113 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
1114 if ( text
.CmpNoCase(entryLabel
) == 0 )
1117 useValue
= m_choices
.GetValue(i
);
1122 bool asText
= false;
1124 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
1126 // If text not any of the choices, store as text instead
1127 // (but only if we are wxEditEnumProperty)
1128 if ( useIndex
== -1 && isEdit
)
1133 int setAsNextIndex
= -2;
1137 setAsNextIndex
= -1;
1140 else if ( useIndex
!= GetIndex() )
1142 if ( useIndex
!= -1 )
1144 setAsNextIndex
= useIndex
;
1145 value
= (long)useValue
;
1149 setAsNextIndex
= -1;
1150 value
= wxPGVariant_MinusOne
;
1154 if ( setAsNextIndex
!= -2 )
1156 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1157 // validation purposes only, and index must not be changed
1158 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1159 ms_nextIndex
= setAsNextIndex
;
1161 if ( isEdit
|| setAsNextIndex
!= -1 )
1169 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1171 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1175 if ( argFlags
& wxPG_FULL_VALUE
)
1177 ms_nextIndex
= GetIndexForValue( intVal
);
1181 if ( intVal
!= GetIndex() )
1183 ms_nextIndex
= intVal
;
1187 if ( ms_nextIndex
!= -2 )
1189 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1190 intVal
= m_choices
.GetValue(intVal
);
1192 variant
= (long)intVal
;
1201 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1207 void wxEnumProperty::SetIndex( int index
)
1213 int wxEnumProperty::GetIndex() const
1215 if ( m_value
.IsNull() )
1218 if ( ms_nextIndex
!= -2 )
1219 return ms_nextIndex
;
1224 // -----------------------------------------------------------------------
1225 // wxEditEnumProperty
1226 // -----------------------------------------------------------------------
1228 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1230 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1232 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1233 const long* values
, const wxString
& value
)
1234 : wxEnumProperty(label
,name
,labels
,values
,0)
1239 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1240 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1241 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1246 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1247 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1248 : wxEnumProperty(label
,name
,labels
,values
,0)
1253 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1254 wxPGChoices
& choices
, const wxString
& value
)
1255 : wxEnumProperty(label
,name
,choices
,0)
1260 wxEditEnumProperty::~wxEditEnumProperty()
1264 // -----------------------------------------------------------------------
1266 // -----------------------------------------------------------------------
1268 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1270 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1272 void wxFlagsProperty::Init()
1274 long value
= m_value
;
1277 // Generate children
1281 unsigned int prevChildCount
= m_children
.size();
1284 if ( prevChildCount
)
1286 wxPropertyGridPageState
* state
= GetParentState();
1288 // State safety check (it may be NULL in immediate parent)
1293 wxPGProperty
* selected
= state
->GetSelection();
1296 if ( selected
->GetParent() == this )
1297 oldSel
= selected
->GetIndexInParent();
1298 else if ( selected
== this )
1302 state
->DoClearSelection();
1305 // Delete old children
1306 for ( i
=0; i
<prevChildCount
; i
++ )
1307 delete m_children
[i
];
1311 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1312 // to child bool property controls.
1313 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1314 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1317 if ( m_choices
.IsOk() )
1319 const wxPGChoices
& choices
= m_choices
;
1321 for ( i
=0; i
<GetItemCount(); i
++ )
1324 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1326 wxPGProperty
* boolProp
;
1327 wxString label
= GetLabel(i
);
1330 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1332 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1337 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1339 if ( attrUseCheckBox
)
1340 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1343 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1345 AddPrivateChild(boolProp
);
1348 m_oldChoicesData
= m_choices
.GetDataPtr();
1351 m_oldValue
= m_value
;
1353 if ( prevChildCount
)
1354 SubPropsChanged(oldSel
);
1357 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1358 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1360 m_oldChoicesData
= NULL
;
1364 m_choices
.Set(labels
,values
);
1366 wxASSERT( GetItemCount() );
1372 m_value
= wxPGVariant_Zero
;
1376 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1377 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1378 : wxPGProperty(label
,name
)
1380 m_oldChoicesData
= NULL
;
1382 if ( &labels
&& labels
.size() )
1384 m_choices
.Set(labels
,values
);
1386 wxASSERT( GetItemCount() );
1388 SetValue( (long)value
);
1392 m_value
= wxPGVariant_Zero
;
1396 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1397 wxPGChoices
& choices
, long value
)
1398 : wxPGProperty(label
,name
)
1400 m_oldChoicesData
= NULL
;
1402 if ( choices
.IsOk() )
1404 m_choices
.Assign(choices
);
1406 wxASSERT( GetItemCount() );
1412 m_value
= wxPGVariant_Zero
;
1416 wxFlagsProperty::~wxFlagsProperty()
1420 void wxFlagsProperty::OnSetValue()
1422 if ( !m_choices
.IsOk() || !GetItemCount() )
1424 m_value
= wxPGVariant_Zero
;
1428 long val
= m_value
.GetLong();
1432 // normalize the value (i.e. remove extra flags)
1434 const wxPGChoices
& choices
= m_choices
;
1435 for ( i
= 0; i
< GetItemCount(); i
++ )
1437 fullFlags
|= choices
.GetValue(i
);
1444 // Need to (re)init now?
1445 if ( GetChildCount() != GetItemCount() ||
1446 m_choices
.GetDataPtr() != m_oldChoicesData
)
1452 long newFlags
= m_value
;
1454 if ( newFlags
!= m_oldValue
)
1456 // Set child modified states
1458 const wxPGChoices
& choices
= m_choices
;
1459 for ( i
= 0; i
<GetItemCount(); i
++ )
1463 flag
= choices
.GetValue(i
);
1465 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1466 Item(i
)->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1469 m_oldValue
= newFlags
;
1473 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1474 int WXUNUSED(argFlags
) ) const
1478 if ( !m_choices
.IsOk() )
1483 const wxPGChoices
& choices
= m_choices
;
1485 for ( i
= 0; i
< GetItemCount(); i
++ )
1488 doAdd
= ( flags
& choices
.GetValue(i
) );
1492 text
+= choices
.GetLabel(i
);
1497 // remove last comma
1498 if ( text
.Len() > 1 )
1499 text
.Truncate ( text
.Len() - 2 );
1504 // Translate string into flag tokens
1505 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1507 if ( !m_choices
.IsOk() )
1512 // semicolons are no longer valid delimeters
1513 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1515 if ( token
.length() )
1517 // Determine which one it is
1518 long bit
= IdToBit( token
);
1531 WX_PG_TOKENIZER1_END()
1533 if ( variant
!= (long)newFlags
)
1535 variant
= (long)newFlags
;
1542 // Converts string id to a relevant bit.
1543 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1546 for ( i
= 0; i
< GetItemCount(); i
++ )
1548 if ( id
== GetLabel(i
) )
1550 return m_choices
.GetValue(i
);
1556 void wxFlagsProperty::RefreshChildren()
1558 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1560 int flags
= m_value
.GetLong();
1562 const wxPGChoices
& choices
= m_choices
;
1564 for ( i
= 0; i
< GetItemCount(); i
++ )
1568 flag
= choices
.GetValue(i
);
1570 long subVal
= flags
& flag
;
1571 wxPGProperty
* p
= Item(i
);
1573 if ( subVal
!= (m_oldValue
& flag
) )
1574 p
->ChangeFlag( wxPG_PROP_MODIFIED
, true );
1576 p
->SetValue( subVal
?true:false );
1582 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1584 wxVariant
& childValue
) const
1586 long oldValue
= thisValue
.GetLong();
1587 long val
= childValue
.GetLong();
1588 unsigned long vi
= m_choices
.GetValue(childIndex
);
1591 return (long) (oldValue
| vi
);
1593 return (long) (oldValue
& ~(vi
));
1596 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1598 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1599 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1601 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1603 Item(i
)->SetAttribute(name
, value
);
1605 // Must return false so that the attribute is stored in
1606 // flag property's actual property storage
1612 // -----------------------------------------------------------------------
1614 // -----------------------------------------------------------------------
1616 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1618 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1619 : wxLongStringProperty(name
,label
,value
)
1621 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1624 wxDirProperty::~wxDirProperty() { }
1626 wxValidator
* wxDirProperty::DoGetValidator() const
1628 return wxFileProperty::GetClassValidator();
1631 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1633 // Update property value from editor, if necessary
1634 wxSize
dlg_sz(300,400);
1636 wxString
dlgMessage(m_dlgMessage
);
1637 if ( dlgMessage
.empty() )
1638 dlgMessage
= _("Choose a directory:");
1639 wxDirDialog
dlg( propGrid
,
1643 #if !wxPG_SMALL_SCREEN
1644 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1652 if ( dlg
.ShowModal() == wxID_OK
)
1654 value
= dlg
.GetPath();
1660 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1662 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1664 m_dlgMessage
= value
.GetString();
1670 // -----------------------------------------------------------------------
1671 // wxPGFileDialogAdapter
1672 // -----------------------------------------------------------------------
1674 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1676 wxFileProperty
* fileProp
= NULL
;
1680 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1682 fileProp
= ((wxFileProperty
*)property
);
1683 wxFileName filename
= fileProp
->GetValue().GetString();
1684 path
= filename
.GetPath();
1685 indFilter
= fileProp
->m_indFilter
;
1687 if ( !path
.length() && fileProp
->m_basePath
.length() )
1688 path
= fileProp
->m_basePath
;
1692 wxFileName
fn(property
->GetValue().GetString());
1693 path
= fn
.GetPath();
1696 wxFileDialog
dlg( propGrid
->GetPanel(),
1697 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1698 property
->GetAttribute(wxS("InitialPath"), path
),
1700 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1702 wxDefaultPosition
);
1704 if ( indFilter
>= 0 )
1705 dlg
.SetFilterIndex( indFilter
);
1707 if ( dlg
.ShowModal() == wxID_OK
)
1710 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1711 SetValue( dlg
.GetPath() );
1717 // -----------------------------------------------------------------------
1719 // -----------------------------------------------------------------------
1721 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1722 wxString
,const wxString
&,TextCtrlAndButton
)
1724 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1725 const wxString
& value
) : wxPGProperty(label
,name
)
1727 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1729 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1734 wxFileProperty::~wxFileProperty() {}
1736 wxValidator
* wxFileProperty::GetClassValidator()
1738 #if wxUSE_VALIDATORS
1739 WX_PG_DOGETVALIDATOR_ENTRY()
1741 // Atleast wxPython 2.6.2.1 required that the string argument is given
1743 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1745 wxArrayString exChars
;
1746 exChars
.Add(wxS("?"));
1747 exChars
.Add(wxS("*"));
1748 exChars
.Add(wxS("|"));
1749 exChars
.Add(wxS("<"));
1750 exChars
.Add(wxS(">"));
1751 exChars
.Add(wxS("\""));
1753 validator
->SetExcludes(exChars
);
1755 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1761 wxValidator
* wxFileProperty::DoGetValidator() const
1763 return GetClassValidator();
1766 void wxFileProperty::OnSetValue()
1768 const wxString
& fnstr
= m_value
.GetString();
1770 wxFileName filename
= fnstr
;
1772 if ( !filename
.HasName() )
1774 m_value
= wxPGVariant_EmptyString
;
1777 // Find index for extension.
1778 if ( m_indFilter
< 0 && fnstr
.length() )
1780 wxString ext
= filename
.GetExt();
1783 size_t len
= m_wildcard
.length();
1785 pos
= m_wildcard
.find(wxS("|"), pos
);
1786 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1788 size_t ext_begin
= pos
+ 3;
1790 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1791 if ( pos
== wxString::npos
)
1793 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1795 if ( found_ext
.length() > 0 )
1797 if ( found_ext
[0] == wxS('*') )
1799 m_indFilter
= curind
;
1802 if ( ext
.CmpNoCase(found_ext
) == 0 )
1804 m_indFilter
= curind
;
1810 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1817 wxFileName
wxFileProperty::GetFileName() const
1819 wxFileName filename
;
1821 if ( !m_value
.IsNull() )
1822 filename
= m_value
.GetString();
1827 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1828 int argFlags
) const
1830 wxFileName filename
= value
.GetString();
1832 if ( !filename
.HasName() )
1833 return wxEmptyString
;
1835 wxString fullName
= filename
.GetFullName();
1836 if ( !fullName
.length() )
1837 return wxEmptyString
;
1839 if ( argFlags
& wxPG_FULL_VALUE
)
1841 return filename
.GetFullPath();
1843 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1845 if ( m_basePath
.Length() )
1847 wxFileName
fn2(filename
);
1848 fn2
.MakeRelativeTo(m_basePath
);
1849 return fn2
.GetFullPath();
1851 return filename
.GetFullPath();
1854 return filename
.GetFullName();
1857 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1859 return new wxPGFileDialogAdapter();
1862 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1864 wxFileName filename
= variant
.GetString();
1866 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1868 if ( filename
!= text
)
1876 if ( filename
.GetFullName() != text
)
1878 wxFileName fn
= filename
;
1879 fn
.SetFullName(text
);
1880 variant
= fn
.GetFullPath();
1888 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1890 // Return false on some occasions to make sure those attribs will get
1891 // stored in m_attributes.
1892 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1894 if ( value
.GetLong() )
1895 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1897 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1900 else if ( name
== wxPG_FILE_WILDCARD
)
1902 m_wildcard
= value
.GetString();
1904 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1906 m_basePath
= value
.GetString();
1908 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1909 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1911 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1913 m_initialPath
= value
.GetString();
1916 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1918 m_dlgTitle
= value
.GetString();
1924 // -----------------------------------------------------------------------
1925 // wxPGLongStringDialogAdapter
1926 // -----------------------------------------------------------------------
1928 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1930 wxString val1
= property
->GetValueAsString(0);
1931 wxString val_orig
= val1
;
1934 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1935 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1937 value
= wxString(val1
);
1939 // Run editor dialog.
1940 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1942 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1943 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1947 if ( val1
!= val_orig
)
1956 // -----------------------------------------------------------------------
1957 // wxLongStringProperty
1958 // -----------------------------------------------------------------------
1960 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1961 wxString
,const wxString
&,TextCtrlAndButton
)
1963 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1964 const wxString
& value
) : wxPGProperty(label
,name
)
1969 wxLongStringProperty::~wxLongStringProperty() {}
1971 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1972 int WXUNUSED(argFlags
) ) const
1977 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1980 if ( propGrid
->IsMainButtonEvent(event
) )
1983 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1985 wxString val1
= useValue
.GetString();
1986 wxString val_orig
= val1
;
1989 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1990 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1992 value
= wxString(val1
);
1994 // Run editor dialog.
1995 if ( OnButtonClick(propGrid
,value
) )
1997 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1998 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
2002 if ( val1
!= val_orig
)
2004 SetValueInEvent( val1
);
2012 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
2014 return DisplayEditorDialog(this, propGrid
, value
);
2017 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
2020 // launch editor dialog
2021 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
2022 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
2024 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
2026 // Multi-line text editor dialog.
2027 #if !wxPG_SMALL_SCREEN
2028 const int spacing
= 8;
2030 const int spacing
= 4;
2032 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2033 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2034 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
2035 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
2037 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
2038 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
2040 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2041 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
2042 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
2043 buttonSizer
->Realize();
2044 topsizer
->Add( buttonSizer
, 0,
2045 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
2048 dlg
->SetSizer( topsizer
);
2049 topsizer
->SetSizeHints( dlg
);
2051 #if !wxPG_SMALL_SCREEN
2052 dlg
->SetSize(400,300);
2054 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
2057 int res
= dlg
->ShowModal();
2059 if ( res
== wxID_OK
)
2061 value
= ed
->GetValue();
2069 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2071 if ( variant
!= text
)
2079 #if wxUSE_EDITABLELISTBOX
2081 // -----------------------------------------------------------------------
2082 // wxPGArrayEditorDialog
2083 // -----------------------------------------------------------------------
2085 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog
, wxDialog
)
2086 EVT_IDLE(wxPGArrayEditorDialog::OnIdle
)
2089 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog
, wxDialog
)
2091 #include "wx/editlbox.h"
2092 #include "wx/listctrl.h"
2094 // -----------------------------------------------------------------------
2096 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2098 // Repair focus - wxEditableListBox has bitmap buttons, which
2099 // get focus, and lose focus (into the oblivion) when they
2100 // become disabled due to change in control state.
2102 wxWindow
* lastFocused
= m_lastFocused
;
2103 wxWindow
* focus
= ::wxWindow::FindFocus();
2105 // If last focused control became disabled, set focus back to
2106 // wxEditableListBox
2107 if ( lastFocused
&& focus
!= lastFocused
&&
2108 lastFocused
->GetParent() == m_elbSubPanel
&&
2109 !lastFocused
->IsEnabled() )
2111 m_elb
->GetListCtrl()->SetFocus();
2114 m_lastFocused
= focus
;
2119 // -----------------------------------------------------------------------
2121 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2127 // -----------------------------------------------------------------------
2129 void wxPGArrayEditorDialog::Init()
2131 m_lastFocused
= NULL
;
2132 m_hasCustomNewAction
= false;
2133 m_itemPendingAtIndex
= -1;
2136 // -----------------------------------------------------------------------
2138 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow
*parent
,
2139 const wxString
& message
,
2140 const wxString
& caption
,
2147 Create(parent
,message
,caption
,style
,pos
,sz
);
2150 // -----------------------------------------------------------------------
2152 bool wxPGArrayEditorDialog::Create( wxWindow
*parent
,
2153 const wxString
& message
,
2154 const wxString
& caption
,
2159 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2160 // FIXME: This should be only a temporary fix.
2163 int useStyle
= wxCAPTION
;
2165 int useStyle
= style
;
2168 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2170 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2172 #if !wxPG_SMALL_SCREEN
2173 const int spacing
= 4;
2175 const int spacing
= 3;
2180 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2183 if ( message
.length() )
2184 topsizer
->Add( new wxStaticText(this,-1,message
),
2185 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2187 m_elb
= new wxEditableListBox(this, wxID_ANY
, message
,
2194 // Populate the list box
2196 for ( unsigned int i
=0; i
<ArrayGetCount(); i
++ )
2197 arr
.push_back(ArrayGet(i
));
2198 m_elb
->SetStrings(arr
);
2200 // Connect event handlers
2202 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2204 but
= m_elb
->GetNewButton();
2205 m_elbSubPanel
= but
->GetParent();
2206 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2207 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick
),
2210 but
= m_elb
->GetDelButton();
2211 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2212 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick
),
2215 but
= m_elb
->GetUpButton();
2216 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2217 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick
),
2220 but
= m_elb
->GetDownButton();
2221 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2222 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick
),
2225 lc
->Connect(lc
->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT
,
2226 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit
),
2229 topsizer
->Add( m_elb
, 1, wxEXPAND
, spacing
);
2231 // Standard dialog buttons
2232 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2233 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2234 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2235 buttonSizer
->Realize();
2236 topsizer
->Add( buttonSizer
, 0,
2237 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2242 SetSizer( topsizer
);
2243 topsizer
->SetSizeHints( this );
2245 #if !wxPG_SMALL_SCREEN
2246 if ( sz
.x
== wxDefaultSize
.x
&&
2247 sz
.y
== wxDefaultSize
.y
)
2248 SetSize( wxSize(275,360) );
2256 // -----------------------------------------------------------------------
2258 int wxPGArrayEditorDialog::GetSelection() const
2260 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2262 int index
= lc
->GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
2269 // -----------------------------------------------------------------------
2271 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent
& event
)
2273 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2274 int newItemIndex
= lc
->GetItemCount() - 1;
2276 if ( m_hasCustomNewAction
)
2279 if ( OnCustomNewAction(&str
) )
2281 if ( ArrayInsert(str
, newItemIndex
) )
2283 lc
->InsertItem(newItemIndex
, str
);
2288 // Do *not* skip the event! We do not want the wxEditableListBox
2293 m_itemPendingAtIndex
= newItemIndex
;
2299 // -----------------------------------------------------------------------
2301 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent
& event
)
2303 int index
= GetSelection();
2306 ArrayRemoveAt( index
);
2313 // -----------------------------------------------------------------------
2315 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent
& event
)
2317 int index
= GetSelection();
2320 ArraySwap(index
-1,index
);
2327 // -----------------------------------------------------------------------
2329 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent
& event
)
2331 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2332 int index
= GetSelection();
2333 int lastStringIndex
= lc
->GetItemCount() - 1;
2334 if ( index
>= 0 && index
< lastStringIndex
)
2336 ArraySwap(index
, index
+1);
2343 // -----------------------------------------------------------------------
2345 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent
& event
)
2347 wxString str
= event
.GetLabel();
2349 if ( m_itemPendingAtIndex
>= 0 )
2352 if ( ArrayInsert(str
, m_itemPendingAtIndex
) )
2358 // Editable list box doesn't really respect Veto(), but
2359 // it recognizes if no text was added, so we simulate
2361 event
.m_item
.SetText(wxEmptyString
);
2362 m_elb
->GetListCtrl()->SetItemText(m_itemPendingAtIndex
,
2370 // Change an existing item
2371 int index
= GetSelection();
2372 wxASSERT( index
!= wxNOT_FOUND
);
2373 if ( ArraySet(index
, str
) )
2382 #endif // wxUSE_EDITABLELISTBOX
2384 // -----------------------------------------------------------------------
2385 // wxPGArrayStringEditorDialog
2386 // -----------------------------------------------------------------------
2388 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2390 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2393 // -----------------------------------------------------------------------
2395 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2397 return m_array
[index
];
2400 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2402 return m_array
.size();
2405 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2410 m_array
.Insert(str
,index
);
2414 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2416 m_array
[index
] = str
;
2420 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2422 m_array
.RemoveAt(index
);
2425 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2427 wxString old_str
= m_array
[first
];
2428 wxString new_str
= m_array
[second
];
2429 m_array
[first
] = new_str
;
2430 m_array
[second
] = old_str
;
2433 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2434 : wxPGArrayEditorDialog()
2439 void wxPGArrayStringEditorDialog::Init()
2441 m_pCallingClass
= NULL
;
2445 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString
* resString
)
2447 return m_pCallingClass
->OnCustomStringEdit(m_parent
, *resString
);
2450 // -----------------------------------------------------------------------
2451 // wxArrayStringProperty
2452 // -----------------------------------------------------------------------
2454 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2455 wxPGProperty
, // Property we inherit from
2456 wxArrayString
, // Value type name
2457 const wxArrayString
&, // Value type, as given in constructor
2458 TextCtrlAndButton
) // Initial editor
2460 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2461 const wxString
& name
,
2462 const wxArrayString
& array
)
2463 : wxPGProperty(label
,name
)
2469 wxArrayStringProperty::~wxArrayStringProperty() { }
2471 void wxArrayStringProperty::OnSetValue()
2473 GenerateValueAsString();
2477 wxArrayStringProperty::ConvertArrayToString(const wxArrayString
& arr
,
2479 const wxUniChar
& delimiter
) const
2481 if ( delimiter
== '"' || delimiter
== '\'' )
2484 ArrayStringToString(*pString
,
2487 Escape
| QuoteStrings
);
2491 // Regular delimiter
2492 ArrayStringToString(*pString
,
2499 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2500 int argFlags
) const
2503 // If this is called from GetValueAsString(), return cached string
2504 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2509 wxArrayString arr
= m_value
.GetArrayString();
2511 ConvertArrayToString(arr
, &s
, m_delimiter
);
2515 // Converts wxArrayString to a string separated by delimeters and spaces.
2516 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2519 wxArrayStringProperty::ArrayStringToString( wxString
& dst
,
2520 const wxArrayString
& src
,
2521 wxUniChar delimiter
, int flags
)
2527 unsigned int itemCount
= src
.size();
2531 if ( flags
& Escape
)
2534 pdr
= wxS("\\") + static_cast<wchar_t>(delimiter
);
2538 dst
.append( preas
);
2540 wxString
delimStr(delimiter
);
2542 for ( i
= 0; i
< itemCount
; i
++ )
2544 wxString
str( src
.Item(i
) );
2546 // Do some character conversion.
2547 // Converts \ to \\ and $delimiter to \$delimiter
2548 // Useful when quoting.
2549 if ( flags
& Escape
)
2551 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2553 str
.Replace( preas
, pdr
, true );
2558 if ( i
< (itemCount
-1) )
2560 dst
.append( delimStr
);
2561 dst
.append( wxS(" ") );
2562 dst
.append( preas
);
2564 else if ( flags
& QuoteStrings
)
2565 dst
.append( delimStr
);
2569 void wxArrayStringProperty::GenerateValueAsString()
2571 wxArrayString arr
= m_value
.GetArrayString();
2572 ConvertArrayToString(arr
, &m_display
, m_delimiter
);
2575 // Default implementation doesn't do anything.
2576 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2581 wxPGArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2583 return new wxPGArrayStringEditorDialog();
2586 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2587 wxWindow
* WXUNUSED(primaryCtrl
),
2591 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2593 if ( !propGrid
->EditorValidate() )
2596 // Create editor dialog.
2597 wxPGArrayEditorDialog
* dlg
= CreateEditorDialog();
2598 #if wxUSE_VALIDATORS
2599 wxValidator
* validator
= GetValidator();
2600 wxPGInDialogValidator dialogValidator
;
2603 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2606 strEdDlg
->SetCustomButton(cbt
, this);
2608 dlg
->SetDialogValue( useValue
);
2609 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2611 #if !wxPG_SMALL_SCREEN
2612 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2621 int res
= dlg
->ShowModal();
2623 if ( res
== wxID_OK
&& dlg
->IsModified() )
2625 wxVariant value
= dlg
->GetDialogValue();
2626 if ( !value
.IsNull() )
2628 wxArrayString actualValue
= value
.GetArrayString();
2630 ConvertArrayToString(actualValue
, &tempStr
, m_delimiter
);
2631 #if wxUSE_VALIDATORS
2632 if ( dialogValidator
.DoValidate(propGrid
, validator
,
2636 SetValueInEvent( actualValue
);
2653 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2657 if ( propGrid
->IsMainButtonEvent(event
) )
2658 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2662 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
,
2663 const wxString
& text
, int ) const
2667 if ( m_delimiter
== '"' || m_delimiter
== '\'' )
2670 WX_PG_TOKENIZER2_BEGIN(text
, m_delimiter
)
2672 // Need to replace backslashes with empty characters
2673 // (opposite what is done in ConvertArrayToString()).
2674 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2678 WX_PG_TOKENIZER2_END()
2682 // Regular delimiter
2683 WX_PG_TOKENIZER1_BEGIN(text
, m_delimiter
)
2685 WX_PG_TOKENIZER1_END()
2693 bool wxArrayStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
2695 if ( name
== wxPG_ARRAY_DELIMITER
)
2697 m_delimiter
= value
.GetChar();
2698 GenerateValueAsString();
2704 // -----------------------------------------------------------------------
2705 // wxPGInDialogValidator
2706 // -----------------------------------------------------------------------
2708 #if wxUSE_VALIDATORS
2709 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2710 wxValidator
* validator
,
2711 const wxString
& value
)
2716 wxTextCtrl
* tc
= m_textCtrl
;
2721 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2722 wxPoint(30000,30000));
2729 tc
->SetValue(value
);
2731 validator
->SetWindow(tc
);
2732 bool res
= validator
->Validate(propGrid
);
2737 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2738 wxValidator
* WXUNUSED(validator
),
2739 const wxString
& WXUNUSED(value
) )
2745 // -----------------------------------------------------------------------
2747 #endif // wxUSE_PROPGRID