1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/props.cpp
3 // Purpose: Basic Property Classes
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
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"
36 #include "wx/cursor.h"
37 #include "wx/dialog.h"
38 #include "wx/settings.h"
39 #include "wx/msgdlg.h"
40 #include "wx/choice.h"
41 #include "wx/stattext.h"
42 #include "wx/scrolwin.h"
43 #include "wx/dirdlg.h"
44 #include "wx/combobox.h"
45 #include "wx/layout.h"
47 #include "wx/textdlg.h"
48 #include "wx/filedlg.h"
52 #include "wx/filename.h"
54 #include "wx/propgrid/propgrid.h"
56 #define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
59 // -----------------------------------------------------------------------
61 // -----------------------------------------------------------------------
63 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxStringProperty
,wxPGProperty
,
64 wxString
,const wxString
&,TextCtrl
)
66 wxStringProperty::wxStringProperty( const wxString
& label
,
68 const wxString
& value
)
69 : wxPGProperty(label
,name
)
74 void wxStringProperty::OnSetValue()
76 if ( !m_value
.IsNull() && m_value
.GetString() == wxS("<composed>") )
77 SetFlag(wxPG_PROP_COMPOSED_VALUE
);
79 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
82 DoGenerateComposedValue(s
);
87 wxStringProperty::~wxStringProperty() { }
89 wxString
wxStringProperty::ValueToString( wxVariant
& value
,
92 wxString s
= value
.GetString();
94 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
96 // Value stored in m_value is non-editable, non-full value
97 if ( (argFlags
& wxPG_FULL_VALUE
) || (argFlags
& wxPG_EDITABLE_VALUE
) )
99 // Calling this under incorrect conditions will fail
100 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
101 "Sorry, currently default wxPGProperty::ValueToString() "
102 "implementation only works if value is m_value." );
104 DoGenerateComposedValue(s
, argFlags
);
110 // If string is password and value is for visual purposes,
111 // then return asterisks instead the actual string.
112 if ( (m_flags
& wxPG_PROP_PASSWORD
) && !(argFlags
& (wxPG_FULL_VALUE
|wxPG_EDITABLE_VALUE
)) )
113 return wxString(wxChar('*'), s
.Length());
118 bool wxStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
120 if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
121 return wxPGProperty::StringToValue(variant
, text
, argFlags
);
123 if ( variant
!= text
)
132 bool wxStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
134 if ( name
== wxPG_STRING_PASSWORD
)
136 m_flags
&= ~(wxPG_PROP_PASSWORD
);
137 if ( value
.GetLong() ) m_flags
|= wxPG_PROP_PASSWORD
;
144 // -----------------------------------------------------------------------
146 // -----------------------------------------------------------------------
148 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
151 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
152 long value
) : wxPGProperty(label
,name
)
157 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
158 const wxLongLong
& value
) : wxPGProperty(label
,name
)
160 SetValue(WXVARIANT(value
));
163 wxIntProperty::~wxIntProperty() { }
165 wxString
wxIntProperty::ValueToString( wxVariant
& value
,
166 int WXUNUSED(argFlags
) ) const
168 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
170 return wxString::Format(wxS("%li"),value
.GetLong());
172 else if ( value
.GetType() == wxPG_VARIANT_TYPE_LONGLONG
)
174 wxLongLong ll
= value
.GetLongLong();
175 return ll
.ToString();
178 return wxEmptyString
;
181 bool wxIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
186 if ( text
.length() == 0 )
192 // We know it is a number, but let's still check
194 if ( text
.IsNumber() )
196 // Remove leading zeroes, so that the number is not interpreted as octal
197 wxString::const_iterator i
= text
.begin();
198 wxString::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
200 int firstNonZeroPos
= 0;
202 for ( ; i
!= iMax
; ++i
)
205 if ( c
!= wxS('0') && c
!= wxS(' ') )
210 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
212 wxString variantType
= variant
.GetType();
213 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
215 wxLongLong_t value64
= 0;
217 if ( useText
.ToLongLong(&value64
, 10) &&
218 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
221 bool doChangeValue
= isPrevLong
;
223 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_LONGLONG
)
225 wxLongLong oldValue
= variant
.GetLongLong();
226 if ( oldValue
.GetValue() != value64
)
227 doChangeValue
= true;
232 wxLongLong
ll(value64
);
238 if ( useText
.ToLong( &value32
, 0 ) )
240 if ( !isPrevLong
|| variant
!= value32
)
247 else if ( argFlags
& wxPG_REPORT_ERROR
)
253 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
255 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
!= (long)value
)
257 variant
= (long)value
;
263 bool wxIntProperty::DoValidation( const wxPGProperty
* property
, wxLongLong_t
& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
266 wxLongLong_t min
= wxINT64_MIN
;
267 wxLongLong_t max
= wxINT64_MAX
;
272 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
273 if ( !variant
.IsNull() )
275 min
= variant
.GetLongLong().GetValue();
279 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
280 if ( !variant
.IsNull() )
282 max
= variant
.GetLongLong().GetValue();
290 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
294 msg
= wxString::Format(
295 _("Value must be %lld or higher."), min
);
297 msg
= wxString::Format(
298 _("Value must be between %lld and %lld."),
300 pValidationInfo
->SetFailureMessage(msg
);
302 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
305 value
= max
- (min
- value
);
314 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
318 msg
= wxString::Format(
319 _("Value must be %lld or lower."), max
);
321 msg
= wxString::Format(
322 _("Value must be between %lld and %lld."),
324 pValidationInfo
->SetFailureMessage(msg
);
326 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
329 value
= min
+ (value
- max
);
336 bool wxIntProperty::ValidateValue( wxVariant
& value
,
337 wxPGValidationInfo
& validationInfo
) const
339 wxLongLong_t ll
= value
.GetLongLong().GetValue();
340 return DoValidation(this, ll
, &validationInfo
,
341 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
344 wxValidator
* wxIntProperty::GetClassValidator()
347 WX_PG_DOGETVALIDATOR_ENTRY()
349 // Atleast wxPython 2.6.2.1 required that the string argument is given
351 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_NUMERIC
,&v
);
353 WX_PG_DOGETVALIDATOR_EXIT(validator
)
359 wxValidator
* wxIntProperty::DoGetValidator() const
361 return GetClassValidator();
364 // -----------------------------------------------------------------------
366 // -----------------------------------------------------------------------
369 #define wxPG_UINT_TEMPLATE_MAX 8
371 static const wxChar
* const gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
372 wxT("%x"),wxT("0x%x"),wxT("$%x"),
373 wxT("%X"),wxT("0x%X"),wxT("$%X"),
377 static const char* const gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
378 "%" wxLongLongFmtSpec
"x",
379 "0x%" wxLongLongFmtSpec
"x",
380 "$%" wxLongLongFmtSpec
"x",
381 "%" wxLongLongFmtSpec
"X",
382 "0x%" wxLongLongFmtSpec
"X",
383 "$%" wxLongLongFmtSpec
"X",
384 "%" wxLongLongFmtSpec
"u",
385 "%" wxLongLongFmtSpec
"o"
388 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
389 long,unsigned long,TextCtrl
)
391 void wxUIntProperty::Init()
393 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
395 m_prefix
= wxPG_PREFIX_NONE
;
398 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
399 unsigned long value
) : wxPGProperty(label
,name
)
402 SetValue((long)value
);
405 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
406 const wxULongLong
& value
) : wxPGProperty(label
,name
)
409 SetValue(WXVARIANT(value
));
412 wxUIntProperty::~wxUIntProperty() { }
414 wxString
wxUIntProperty::ValueToString( wxVariant
& value
,
415 int WXUNUSED(argFlags
) ) const
417 size_t index
= m_base
+ m_prefix
;
418 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
419 index
= wxPG_BASE_DEC
;
421 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
423 return wxString::Format(gs_uintTemplates32
[index
],
424 (unsigned long)value
.GetLong());
427 wxULongLong ull
= value
.GetULongLong();
429 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
432 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
434 wxString variantType
= variant
.GetType();
435 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
437 if ( text
.length() == 0 )
444 if ( text
[0] == wxS('$') )
447 wxULongLong_t value64
= 0;
448 wxString s
= text
.substr(start
, text
.length() - start
);
450 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
452 if ( value64
>= LONG_MAX
)
454 bool doChangeValue
= isPrevLong
;
456 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_ULONGLONG
)
458 wxULongLong oldValue
= variant
.GetULongLong();
459 if ( oldValue
.GetValue() != value64
)
460 doChangeValue
= true;
465 variant
= wxULongLong(value64
);
471 unsigned long value32
= wxLongLong(value64
).GetLo();
472 if ( !isPrevLong
|| m_value
!= (long)value32
)
474 variant
= (long)value32
;
483 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
485 if ( variant
!= (long)number
)
487 variant
= (long)number
;
493 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
496 wxULongLong_t ll
= value
.GetULongLong().GetValue();
498 wxULongLong_t min
= 0;
499 wxULongLong_t max
= wxUINT64_MAX
;
502 variant
= GetAttribute(wxPGGlobalVars
->m_strMin
);
503 if ( !variant
.IsNull() )
505 min
= variant
.GetULongLong().GetValue();
508 validationInfo
.SetFailureMessage(
509 wxString::Format(_("Value must be %llu or higher"),min
)
514 variant
= GetAttribute(wxPGGlobalVars
->m_strMax
);
515 if ( !variant
.IsNull() )
517 max
= variant
.GetULongLong().GetValue();
520 validationInfo
.SetFailureMessage(
521 wxString::Format(_("Value must be %llu or less"),max
)
530 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
532 if ( name
== wxPG_UINT_BASE
)
534 int val
= value
.GetLong();
536 m_realBase
= (wxByte
) val
;
537 if ( m_realBase
> 16 )
541 // Translate logical base to a template array index
543 if ( val
== wxPG_BASE_HEX
)
545 else if ( val
== wxPG_BASE_DEC
)
547 else if ( val
== wxPG_BASE_HEXL
)
551 else if ( name
== wxPG_UINT_PREFIX
)
553 m_prefix
= (wxByte
) value
.GetLong();
559 // -----------------------------------------------------------------------
561 // -----------------------------------------------------------------------
563 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
564 double,double,TextCtrl
)
566 wxFloatProperty::wxFloatProperty( const wxString
& label
,
567 const wxString
& name
,
569 : wxPGProperty(label
,name
)
575 wxFloatProperty::~wxFloatProperty() { }
577 // This helper method provides standard way for floating point-using
578 // properties to convert values to string.
579 void wxPropertyGrid::DoubleToString(wxString
& target
,
583 wxString
* precTemplate
)
585 if ( precision
>= 0 )
589 precTemplate
= &text1
;
591 if ( !precTemplate
->length() )
593 *precTemplate
= wxS("%.");
594 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
595 *precTemplate
<< wxS('f');
598 target
.Printf( precTemplate
->c_str(), value
);
602 target
.Printf( wxS("%f"), value
);
605 if ( removeZeroes
&& precision
!= 0 && target
.length() )
607 // Remove excess zeroes (do not remove this code just yet,
608 // since sprintf can't do the same consistently across platforms).
609 wxString::const_iterator i
= target
.end() - 1;
610 size_t new_len
= target
.length() - 1;
612 for ( ; i
!= target
.begin(); --i
)
614 if ( *i
!= wxS('0') )
619 wxChar cur_char
= *i
;
620 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
623 if ( new_len
!= target
.length() )
624 target
.resize(new_len
);
628 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
632 if ( !value
.IsNull() )
634 wxPropertyGrid::DoubleToString(text
,
637 !(argFlags
& wxPG_FULL_VALUE
),
643 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
648 if ( text
.length() == 0 )
654 bool res
= text
.ToDouble(&value
);
657 if ( variant
!= value
)
663 else if ( argFlags
& wxPG_REPORT_ERROR
)
669 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
671 wxPGValidationInfo
* pValidationInfo
,
675 double min
= (double)wxINT64_MIN
;
676 double max
= (double)wxINT64_MAX
;
681 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
682 if ( !variant
.IsNull() )
684 min
= variant
.GetDouble();
688 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
689 if ( !variant
.IsNull() )
691 max
= variant
.GetDouble();
699 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
700 pValidationInfo
->SetFailureMessage(
701 wxString::Format(_("Value must be %f or higher"),min
)
703 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
706 value
= max
- (min
- value
);
713 max
= variant
.GetDouble();
716 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
717 pValidationInfo
->SetFailureMessage(
718 wxString::Format(_("Value must be %f or less"),max
)
720 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
723 value
= min
+ (value
- max
);
731 wxFloatProperty::ValidateValue( wxVariant
& value
,
732 wxPGValidationInfo
& validationInfo
) const
734 double fpv
= value
.GetDouble();
735 return DoValidation(this, fpv
, &validationInfo
,
736 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
739 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
741 if ( name
== wxPG_FLOAT_PRECISION
)
743 m_precision
= value
.GetLong();
749 wxValidator
* wxFloatProperty::DoGetValidator() const
751 return wxIntProperty::GetClassValidator();
754 // -----------------------------------------------------------------------
756 // -----------------------------------------------------------------------
758 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
759 // there is a custom GetEditorClass.
761 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
763 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
765 // Select correct editor control.
766 #if wxPG_INCLUDE_CHECKBOX
767 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
768 return wxPGEditor_Choice
;
769 return wxPGEditor_CheckBox
;
771 return wxPGEditor_Choice
;
775 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
776 wxPGProperty(label
,name
)
778 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
780 SetValue(wxPGVariant_Bool(value
));
782 m_flags
|= wxPG_PROP_USE_DCC
;
785 wxBoolProperty::~wxBoolProperty() { }
787 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
790 bool boolValue
= value
.GetBool();
792 // As a fragment of composite string value,
793 // make it a little more readable.
794 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
802 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
803 return wxEmptyString
;
806 if ( wxPGGlobalVars
->m_autoGetTranslation
)
807 notFmt
= _("Not %s");
809 notFmt
= wxS("Not %s");
811 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
815 if ( !(argFlags
& wxPG_FULL_VALUE
) )
817 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
822 if ( boolValue
) text
= wxS("true");
823 else text
= wxS("false");
828 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
830 bool boolValue
= false;
831 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
832 text
.CmpNoCase(wxS("true")) == 0 ||
833 text
.CmpNoCase(m_label
) == 0 )
836 if ( text
.length() == 0 )
842 if ( variant
!= boolValue
)
844 variant
= wxPGVariant_Bool(boolValue
);
850 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
852 bool boolValue
= value
? true : false;
854 if ( variant
!= boolValue
)
856 variant
= wxPGVariant_Bool(boolValue
);
862 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
864 #if wxPG_INCLUDE_CHECKBOX
865 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
867 if ( value
.GetLong() )
868 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
870 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
874 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
876 if ( value
.GetLong() )
877 m_flags
|= wxPG_PROP_USE_DCC
;
879 m_flags
&= ~(wxPG_PROP_USE_DCC
);
885 // -----------------------------------------------------------------------
887 // -----------------------------------------------------------------------
889 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
891 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
893 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
894 const long* values
, int value
) : wxPGProperty(label
,name
)
900 m_choices
.Add(labels
,values
);
902 if ( GetItemCount() )
903 SetValue( (long)value
);
907 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
908 const long* values
, wxPGChoices
* choicesCache
, int value
)
909 : wxPGProperty(label
,name
)
913 wxASSERT( choicesCache
);
915 if ( choicesCache
->IsOk() )
917 m_choices
.Assign( *choicesCache
);
918 m_value
= wxPGVariant_Zero
;
922 m_choices
.Add(labels
,values
);
924 if ( GetItemCount() )
925 SetValue( (long)value
);
929 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
930 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
931 : wxPGProperty(label
,name
)
935 if ( &labels
&& labels
.size() )
937 m_choices
.Set(labels
, values
);
939 if ( GetItemCount() )
940 SetValue( (long)value
);
944 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
945 wxPGChoices
& choices
, int value
)
946 : wxPGProperty(label
,name
)
948 m_choices
.Assign( choices
);
950 if ( GetItemCount() )
951 SetValue( (long)value
);
954 int wxEnumProperty::GetIndexForValue( int value
) const
956 if ( !m_choices
.IsOk() )
959 int intVal
= m_choices
.Index(value
);
966 wxEnumProperty::~wxEnumProperty ()
970 int wxEnumProperty::ms_nextIndex
= -2;
972 void wxEnumProperty::OnSetValue()
974 wxString variantType
= m_value
.GetType();
976 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
978 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
980 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
982 ValueFromString_( m_value
, m_value
.GetString(), 0 );
989 if ( ms_nextIndex
!= -2 )
991 m_index
= ms_nextIndex
;
996 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
998 // Make sure string value is in the list,
999 // unless property has string as preferred value type
1000 // To reduce code size, use conversion here as well
1001 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
1002 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
1003 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
1008 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
1009 int WXUNUSED(argFlags
) ) const
1011 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
1012 return value
.GetString();
1014 int index
= m_choices
.Index(value
.GetLong());
1016 return wxEmptyString
;
1018 return m_choices
.GetLabel(index
);
1021 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1023 return ValueFromString_( variant
, text
, argFlags
);
1026 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
1028 return ValueFromInt_( variant
, intVal
, argFlags
);
1031 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
1036 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
1038 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
1039 if ( text
.CmpNoCase(entryLabel
) == 0 )
1042 useValue
= m_choices
.GetValue(i
);
1047 bool asText
= false;
1049 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
1051 // If text not any of the choices, store as text instead
1052 // (but only if we are wxEditEnumProperty)
1053 if ( useIndex
== -1 && isEdit
)
1058 int setAsNextIndex
= -2;
1062 setAsNextIndex
= -1;
1065 else if ( useIndex
!= GetIndex() )
1067 if ( useIndex
!= -1 )
1069 setAsNextIndex
= useIndex
;
1070 value
= (long)useValue
;
1074 setAsNextIndex
= -1;
1075 value
= wxPGVariant_MinusOne
;
1079 if ( setAsNextIndex
!= -2 )
1081 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1082 // validation purposes only, and index must not be changed
1083 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1084 ms_nextIndex
= setAsNextIndex
;
1086 if ( isEdit
|| setAsNextIndex
!= -1 )
1094 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1096 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1100 if ( argFlags
& wxPG_FULL_VALUE
)
1102 ms_nextIndex
= GetIndexForValue( intVal
);
1106 if ( intVal
!= GetIndex() )
1108 ms_nextIndex
= intVal
;
1112 if ( ms_nextIndex
!= -2 )
1114 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1115 intVal
= m_choices
.GetValue(intVal
);
1117 variant
= (long)intVal
;
1126 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1132 void wxEnumProperty::SetIndex( int index
)
1138 int wxEnumProperty::GetIndex() const
1140 if ( m_value
.IsNull() )
1143 if ( ms_nextIndex
!= -2 )
1144 return ms_nextIndex
;
1149 // -----------------------------------------------------------------------
1150 // wxEditEnumProperty
1151 // -----------------------------------------------------------------------
1153 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1155 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1157 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1158 const long* values
, const wxString
& value
)
1159 : wxEnumProperty(label
,name
,labels
,values
,0)
1164 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1165 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1166 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1171 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1172 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1173 : wxEnumProperty(label
,name
,labels
,values
,0)
1178 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1179 wxPGChoices
& choices
, const wxString
& value
)
1180 : wxEnumProperty(label
,name
,choices
,0)
1185 wxEditEnumProperty::~wxEditEnumProperty()
1189 // -----------------------------------------------------------------------
1191 // -----------------------------------------------------------------------
1193 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1195 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1197 void wxFlagsProperty::Init()
1199 long value
= m_value
;
1202 // Generate children
1206 unsigned int prevChildCount
= m_children
.size();
1209 if ( prevChildCount
)
1211 wxPropertyGridPageState
* state
= GetParentState();
1213 // State safety check (it may be NULL in immediate parent)
1218 wxPGProperty
* selected
= state
->GetSelection();
1221 if ( selected
->GetParent() == this )
1222 oldSel
= selected
->GetIndexInParent();
1223 else if ( selected
== this )
1227 state
->DoClearSelection();
1230 // Delete old children
1231 for ( i
=0; i
<prevChildCount
; i
++ )
1232 delete m_children
[i
];
1236 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1237 // to child bool property controls.
1238 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1239 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1242 if ( m_choices
.IsOk() )
1244 const wxPGChoices
& choices
= m_choices
;
1246 for ( i
=0; i
<GetItemCount(); i
++ )
1249 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1251 wxPGProperty
* boolProp
;
1252 wxString label
= GetLabel(i
);
1255 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1257 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1262 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1264 if ( attrUseCheckBox
)
1265 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1268 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1270 AddPrivateChild(boolProp
);
1273 m_oldChoicesData
= m_choices
.GetDataPtr();
1276 m_oldValue
= m_value
;
1278 if ( prevChildCount
)
1279 SubPropsChanged(oldSel
);
1282 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1283 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1285 m_oldChoicesData
= NULL
;
1289 m_choices
.Set(labels
,values
);
1291 wxASSERT( GetItemCount() );
1297 m_value
= wxPGVariant_Zero
;
1301 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1302 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1303 : wxPGProperty(label
,name
)
1305 m_oldChoicesData
= NULL
;
1307 if ( &labels
&& labels
.size() )
1309 m_choices
.Set(labels
,values
);
1311 wxASSERT( GetItemCount() );
1313 SetValue( (long)value
);
1317 m_value
= wxPGVariant_Zero
;
1321 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1322 wxPGChoices
& choices
, long value
)
1323 : wxPGProperty(label
,name
)
1325 m_oldChoicesData
= NULL
;
1327 if ( choices
.IsOk() )
1329 m_choices
.Assign(choices
);
1331 wxASSERT( GetItemCount() );
1337 m_value
= wxPGVariant_Zero
;
1341 wxFlagsProperty::~wxFlagsProperty()
1345 void wxFlagsProperty::OnSetValue()
1347 if ( !m_choices
.IsOk() || !GetItemCount() )
1349 m_value
= wxPGVariant_Zero
;
1353 long val
= m_value
.GetLong();
1357 // normalize the value (i.e. remove extra flags)
1359 const wxPGChoices
& choices
= m_choices
;
1360 for ( i
= 0; i
< GetItemCount(); i
++ )
1362 fullFlags
|= choices
.GetValue(i
);
1369 // Need to (re)init now?
1370 if ( GetChildCount() != GetItemCount() ||
1371 m_choices
.GetDataPtr() != m_oldChoicesData
)
1377 long newFlags
= m_value
;
1379 if ( newFlags
!= m_oldValue
)
1381 // Set child modified states
1383 const wxPGChoices
& choices
= m_choices
;
1384 for ( i
= 0; i
<GetItemCount(); i
++ )
1388 flag
= choices
.GetValue(i
);
1390 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1391 Item(i
)->SetFlag( wxPG_PROP_MODIFIED
);
1394 m_oldValue
= newFlags
;
1398 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1399 int WXUNUSED(argFlags
) ) const
1403 if ( !m_choices
.IsOk() )
1408 const wxPGChoices
& choices
= m_choices
;
1410 for ( i
= 0; i
< GetItemCount(); i
++ )
1413 doAdd
= ( flags
& choices
.GetValue(i
) );
1417 text
+= choices
.GetLabel(i
);
1422 // remove last comma
1423 if ( text
.Len() > 1 )
1424 text
.Truncate ( text
.Len() - 2 );
1429 // Translate string into flag tokens
1430 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1432 if ( !m_choices
.IsOk() )
1437 // semicolons are no longer valid delimeters
1438 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1440 if ( token
.length() )
1442 // Determine which one it is
1443 long bit
= IdToBit( token
);
1456 WX_PG_TOKENIZER1_END()
1458 if ( variant
!= (long)newFlags
)
1460 variant
= (long)newFlags
;
1467 // Converts string id to a relevant bit.
1468 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1471 for ( i
= 0; i
< GetItemCount(); i
++ )
1473 if ( id
== GetLabel(i
) )
1475 return m_choices
.GetValue(i
);
1481 void wxFlagsProperty::RefreshChildren()
1483 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1485 int flags
= m_value
.GetLong();
1487 const wxPGChoices
& choices
= m_choices
;
1489 for ( i
= 0; i
< GetItemCount(); i
++ )
1493 flag
= choices
.GetValue(i
);
1495 long subVal
= flags
& flag
;
1496 wxPGProperty
* p
= Item(i
);
1498 if ( subVal
!= (m_oldValue
& flag
) )
1499 p
->SetFlag( wxPG_PROP_MODIFIED
);
1501 p
->SetValue( subVal
?true:false );
1507 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1509 wxVariant
& childValue
) const
1511 long oldValue
= thisValue
.GetLong();
1512 long val
= childValue
.GetLong();
1513 unsigned long vi
= m_choices
.GetValue(childIndex
);
1516 return (long) (oldValue
| vi
);
1518 return (long) (oldValue
& ~(vi
));
1521 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1523 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1524 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1526 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1528 Item(i
)->SetAttribute(name
, value
);
1530 // Must return false so that the attribute is stored in
1531 // flag property's actual property storage
1537 // -----------------------------------------------------------------------
1539 // -----------------------------------------------------------------------
1541 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1543 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1544 : wxLongStringProperty(name
,label
,value
)
1546 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1549 wxDirProperty::~wxDirProperty() { }
1551 wxValidator
* wxDirProperty::DoGetValidator() const
1553 return wxFileProperty::GetClassValidator();
1556 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1558 // Update property value from editor, if necessary
1559 wxSize
dlg_sz(300,400);
1561 wxString
dlgMessage(m_dlgMessage
);
1562 if ( dlgMessage
.empty() )
1563 dlgMessage
= _("Choose a directory:");
1564 wxDirDialog
dlg( propGrid
,
1568 #if !wxPG_SMALL_SCREEN
1569 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1577 if ( dlg
.ShowModal() == wxID_OK
)
1579 value
= dlg
.GetPath();
1585 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1587 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1589 m_dlgMessage
= value
.GetString();
1595 // -----------------------------------------------------------------------
1596 // wxPGFileDialogAdapter
1597 // -----------------------------------------------------------------------
1599 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1601 wxFileProperty
* fileProp
= NULL
;
1605 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1607 fileProp
= ((wxFileProperty
*)property
);
1608 wxFileName filename
= fileProp
->GetValue().GetString();
1609 path
= filename
.GetPath();
1610 indFilter
= fileProp
->m_indFilter
;
1612 if ( !path
.length() && fileProp
->m_basePath
.length() )
1613 path
= fileProp
->m_basePath
;
1617 wxFileName
fn(property
->GetValue().GetString());
1618 path
= fn
.GetPath();
1621 wxFileDialog
dlg( propGrid
->GetPanel(),
1622 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1623 property
->GetAttribute(wxS("InitialPath"), path
),
1625 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1627 wxDefaultPosition
);
1629 if ( indFilter
>= 0 )
1630 dlg
.SetFilterIndex( indFilter
);
1632 if ( dlg
.ShowModal() == wxID_OK
)
1635 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1636 SetValue( dlg
.GetPath() );
1642 // -----------------------------------------------------------------------
1644 // -----------------------------------------------------------------------
1646 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1647 wxString
,const wxString
&,TextCtrlAndButton
)
1649 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1650 const wxString
& value
) : wxPGProperty(label
,name
)
1652 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1654 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1659 wxFileProperty::~wxFileProperty() {}
1661 wxValidator
* wxFileProperty::GetClassValidator()
1663 #if wxUSE_VALIDATORS
1664 WX_PG_DOGETVALIDATOR_ENTRY()
1666 // Atleast wxPython 2.6.2.1 required that the string argument is given
1668 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1670 wxArrayString exChars
;
1671 exChars
.Add(wxS("?"));
1672 exChars
.Add(wxS("*"));
1673 exChars
.Add(wxS("|"));
1674 exChars
.Add(wxS("<"));
1675 exChars
.Add(wxS(">"));
1676 exChars
.Add(wxS("\""));
1678 validator
->SetExcludes(exChars
);
1680 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1686 wxValidator
* wxFileProperty::DoGetValidator() const
1688 return GetClassValidator();
1691 void wxFileProperty::OnSetValue()
1693 const wxString
& fnstr
= m_value
.GetString();
1695 wxFileName filename
= fnstr
;
1697 if ( !filename
.HasName() )
1699 m_value
= wxPGVariant_EmptyString
;
1702 // Find index for extension.
1703 if ( m_indFilter
< 0 && fnstr
.length() )
1705 wxString ext
= filename
.GetExt();
1708 size_t len
= m_wildcard
.length();
1710 pos
= m_wildcard
.find(wxS("|"), pos
);
1711 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1713 size_t ext_begin
= pos
+ 3;
1715 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1716 if ( pos
== wxString::npos
)
1718 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1720 if ( found_ext
.length() > 0 )
1722 if ( found_ext
[0] == wxS('*') )
1724 m_indFilter
= curind
;
1727 if ( ext
.CmpNoCase(found_ext
) == 0 )
1729 m_indFilter
= curind
;
1735 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1742 wxFileName
wxFileProperty::GetFileName() const
1744 wxFileName filename
;
1746 if ( !m_value
.IsNull() )
1747 filename
= m_value
.GetString();
1752 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1753 int argFlags
) const
1755 wxFileName filename
= value
.GetString();
1757 if ( !filename
.HasName() )
1758 return wxEmptyString
;
1760 wxString fullName
= filename
.GetFullName();
1761 if ( !fullName
.length() )
1762 return wxEmptyString
;
1764 if ( argFlags
& wxPG_FULL_VALUE
)
1766 return filename
.GetFullPath();
1768 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1770 if ( m_basePath
.Length() )
1772 wxFileName
fn2(filename
);
1773 fn2
.MakeRelativeTo(m_basePath
);
1774 return fn2
.GetFullPath();
1776 return filename
.GetFullPath();
1779 return filename
.GetFullName();
1782 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1784 return new wxPGFileDialogAdapter();
1787 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1789 wxFileName filename
= variant
.GetString();
1791 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1793 if ( filename
!= text
)
1801 if ( filename
.GetFullName() != text
)
1803 wxFileName fn
= filename
;
1804 fn
.SetFullName(text
);
1805 variant
= fn
.GetFullPath();
1813 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1815 // Return false on some occasions to make sure those attribs will get
1816 // stored in m_attributes.
1817 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1819 if ( value
.GetLong() )
1820 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1822 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1825 else if ( name
== wxPG_FILE_WILDCARD
)
1827 m_wildcard
= value
.GetString();
1829 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1831 m_basePath
= value
.GetString();
1833 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1834 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1836 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1838 m_initialPath
= value
.GetString();
1841 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1843 m_dlgTitle
= value
.GetString();
1849 // -----------------------------------------------------------------------
1850 // wxPGLongStringDialogAdapter
1851 // -----------------------------------------------------------------------
1853 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1855 wxString val1
= property
->GetValueAsString(0);
1856 wxString val_orig
= val1
;
1859 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1860 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1862 value
= wxString(val1
);
1864 // Run editor dialog.
1865 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1867 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1868 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1872 if ( val1
!= val_orig
)
1881 // -----------------------------------------------------------------------
1882 // wxLongStringProperty
1883 // -----------------------------------------------------------------------
1885 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1886 wxString
,const wxString
&,TextCtrlAndButton
)
1888 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1889 const wxString
& value
) : wxPGProperty(label
,name
)
1894 wxLongStringProperty::~wxLongStringProperty() {}
1896 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1897 int WXUNUSED(argFlags
) ) const
1902 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1905 if ( propGrid
->IsMainButtonEvent(event
) )
1908 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1910 wxString val1
= useValue
.GetString();
1911 wxString val_orig
= val1
;
1914 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1915 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1917 value
= wxString(val1
);
1919 // Run editor dialog.
1920 if ( OnButtonClick(propGrid
,value
) )
1922 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1923 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1927 if ( val1
!= val_orig
)
1929 SetValueInEvent( val1
);
1937 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1939 return DisplayEditorDialog(this, propGrid
, value
);
1942 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
1945 // launch editor dialog
1946 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
1947 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
1949 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
1951 // Multi-line text editor dialog.
1952 #if !wxPG_SMALL_SCREEN
1953 const int spacing
= 8;
1955 const int spacing
= 4;
1957 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
1958 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1959 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
1960 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
1962 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
1963 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
1965 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
1966 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
1967 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
1968 buttonSizer
->Realize();
1969 topsizer
->Add( buttonSizer
, 0,
1970 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
1973 dlg
->SetSizer( topsizer
);
1974 topsizer
->SetSizeHints( dlg
);
1976 #if !wxPG_SMALL_SCREEN
1977 dlg
->SetSize(400,300);
1979 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
1982 int res
= dlg
->ShowModal();
1984 if ( res
== wxID_OK
)
1986 value
= ed
->GetValue();
1994 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1996 if ( variant
!= text
)
2004 // -----------------------------------------------------------------------
2005 // wxArrayEditorDialog
2006 // -----------------------------------------------------------------------
2008 BEGIN_EVENT_TABLE(wxArrayEditorDialog
, wxDialog
)
2009 EVT_IDLE(wxArrayEditorDialog::OnIdle
)
2010 EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick
)
2011 EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick
)
2012 EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick
)
2013 EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick
)
2014 EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick
)
2015 EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick
)
2016 EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick
)
2017 //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
2020 IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog
, wxDialog
)
2022 #include "wx/statline.h"
2024 // -----------------------------------------------------------------------
2026 void wxArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2029 // Do control focus detection here.
2032 wxWindow
* focused
= FindFocus();
2034 // This strange focus thing is a workaround for wxGTK wxListBox focus
2036 if ( m_curFocus
== 0 && focused
!= m_edValue
&&
2037 focused
!= m_butAdd
&& focused
!= m_butUpdate
&&
2038 m_lbStrings
->GetSelection() >= 0 )
2040 // ListBox was just focused.
2041 m_butAdd
->Enable(false);
2042 m_butUpdate
->Enable(false);
2043 m_butRemove
->Enable(true);
2044 m_butUp
->Enable(true);
2045 m_butDown
->Enable(true);
2048 else if ( (m_curFocus
== 1 && focused
== m_edValue
) /*|| m_curFocus == 2*/ )
2050 // TextCtrl was just focused.
2051 m_butAdd
->Enable(true);
2052 bool upd_enable
= false;
2053 if ( m_lbStrings
->GetCount() && m_lbStrings
->GetSelection() >= 0 )
2055 m_butUpdate
->Enable(upd_enable
);
2056 m_butRemove
->Enable(false);
2057 m_butUp
->Enable(false);
2058 m_butDown
->Enable(false);
2065 // -----------------------------------------------------------------------
2067 wxArrayEditorDialog::wxArrayEditorDialog()
2073 // -----------------------------------------------------------------------
2075 void wxArrayEditorDialog::Init()
2077 m_custBtText
= (const wxChar
*) NULL
;
2080 // -----------------------------------------------------------------------
2082 wxArrayEditorDialog::wxArrayEditorDialog( wxWindow
*parent
,
2083 const wxString
& message
,
2084 const wxString
& caption
,
2091 Create(parent
,message
,caption
,style
,pos
,sz
);
2094 // -----------------------------------------------------------------------
2096 bool wxArrayEditorDialog::Create( wxWindow
*parent
,
2097 const wxString
& message
,
2098 const wxString
& caption
,
2103 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2104 // FIXME: This should be only a temporary fix.
2107 int useStyle
= wxCAPTION
;
2109 int useStyle
= style
;
2112 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2114 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2116 #if !wxPG_SMALL_SCREEN
2117 const int spacing
= 4;
2119 const int spacing
= 3;
2126 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2129 if ( message
.length() )
2130 topsizer
->Add( new wxStaticText(this,-1,message
),
2131 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2134 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2135 m_edValue
= new wxTextCtrl(this,21,wxEmptyString
,
2136 wxDefaultPosition
,wxDefaultSize
,wxTE_PROCESS_ENTER
);
2137 #if wxUSE_VALIDATORS
2138 wxValidator
* validator
= GetTextCtrlValidator();
2141 m_edValue
->SetValidator( *validator
);
2145 rowsizer
->Add( m_edValue
,
2146 1, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2149 m_butAdd
= new wxButton(this,22,_("Add"));
2150 rowsizer
->Add( m_butAdd
,
2151 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxTOP
|wxBOTTOM
|wxRIGHT
, spacing
);
2152 topsizer
->Add( rowsizer
, 0, wxEXPAND
, spacing
);
2155 topsizer
->Add( new wxStaticLine(this,-1),
2156 0, wxEXPAND
|wxBOTTOM
|wxLEFT
|wxRIGHT
, spacing
);
2158 rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
2161 m_lbStrings
= new wxListBox(this, 24, wxDefaultPosition
, wxDefaultSize
);
2163 for ( i
=0; i
<ArrayGetCount(); i
++ )
2164 m_lbStrings
->Append( ArrayGet(i
) );
2165 rowsizer
->Add( m_lbStrings
, 1, wxEXPAND
|wxRIGHT
, spacing
);
2167 // Manipulator buttons
2168 wxBoxSizer
* colsizer
= new wxBoxSizer( wxVERTICAL
);
2172 m_butCustom
= new wxButton(this,28,::wxGetTranslation(m_custBtText
));
2173 colsizer
->Add( m_butCustom
,
2174 0, wxALIGN_CENTER
|wxTOP
/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
2177 m_butUpdate
= new wxButton(this,27,_("Update"));
2178 colsizer
->Add( m_butUpdate
,
2179 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2180 m_butRemove
= new wxButton(this,23,_("Remove"));
2181 colsizer
->Add( m_butRemove
,
2182 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2183 m_butUp
= new wxButton(this,25,_("Up"));
2184 colsizer
->Add( m_butUp
,
2185 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2186 m_butDown
= new wxButton(this,26,_("Down"));
2187 colsizer
->Add( m_butDown
,
2188 0, wxALIGN_CENTER
|wxTOP
, spacing
);
2189 rowsizer
->Add( colsizer
, 0, 0, spacing
);
2191 topsizer
->Add( rowsizer
, 1, wxLEFT
|wxRIGHT
|wxEXPAND
, spacing
);
2194 topsizer
->Add( new wxStaticLine(this,-1),
2195 0, wxEXPAND
|wxTOP
|wxLEFT
|wxRIGHT
, spacing
);
2197 // Standard dialog buttons
2198 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2199 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2200 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2201 buttonSizer
->Realize();
2202 topsizer
->Add( buttonSizer
, 0,
2203 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2206 m_edValue
->SetFocus();
2208 SetSizer( topsizer
);
2209 topsizer
->SetSizeHints( this );
2211 #if !wxPG_SMALL_SCREEN
2212 if ( sz
.x
== wxDefaultSize
.x
&&
2213 sz
.y
== wxDefaultSize
.y
)
2214 SetSize( wxSize(275,360) );
2222 // -----------------------------------------------------------------------
2224 void wxArrayEditorDialog::OnAddClick(wxCommandEvent
& )
2226 wxString text
= m_edValue
->GetValue();
2227 if ( text
.length() )
2229 if ( ArrayInsert( text
, -1 ) )
2231 m_lbStrings
->Append( text
);
2238 // -----------------------------------------------------------------------
2240 void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent
& )
2242 int index
= m_lbStrings
->GetSelection();
2245 ArrayRemoveAt( index
);
2246 m_lbStrings
->Delete ( index
);
2251 // -----------------------------------------------------------------------
2253 void wxArrayEditorDialog::OnUpClick(wxCommandEvent
& )
2255 int index
= m_lbStrings
->GetSelection();
2258 ArraySwap(index
-1,index
);
2259 /*wxString old_str = m_array[index-1];
2260 wxString new_str = m_array[index];
2261 m_array[index-1] = new_str;
2262 m_array[index] = old_str;*/
2263 m_lbStrings
->SetString ( index
-1, ArrayGet(index
-1) );
2264 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2265 m_lbStrings
->SetSelection ( index
-1 );
2270 // -----------------------------------------------------------------------
2272 void wxArrayEditorDialog::OnDownClick(wxCommandEvent
& )
2274 int index
= m_lbStrings
->GetSelection();
2275 int lastStringIndex
= ((int) m_lbStrings
->GetCount()) - 1;
2276 if ( index
>= 0 && index
< lastStringIndex
)
2278 ArraySwap(index
,index
+1);
2279 /*wxString old_str = m_array[index+1];
2280 wxString new_str = m_array[index];
2281 m_array[index+1] = new_str;
2282 m_array[index] = old_str;*/
2283 m_lbStrings
->SetString ( index
+1, ArrayGet(index
+1) );
2284 m_lbStrings
->SetString ( index
, ArrayGet(index
) );
2285 m_lbStrings
->SetSelection ( index
+1 );
2290 // -----------------------------------------------------------------------
2292 void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent
& )
2294 int index
= m_lbStrings
->GetSelection();
2297 wxString str
= m_edValue
->GetValue();
2298 if ( ArraySet(index
,str
) )
2300 m_lbStrings
->SetString ( index
, str
);
2301 //m_array[index] = str;
2307 // -----------------------------------------------------------------------
2309 void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent
& )
2311 int index
= m_lbStrings
->GetSelection();
2314 m_edValue
->SetValue( m_lbStrings
->GetString(index
) );
2318 // -----------------------------------------------------------------------
2319 // wxPGArrayStringEditorDialog
2320 // -----------------------------------------------------------------------
2322 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2324 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxArrayEditorDialog
)
2325 EVT_BUTTON(28, wxPGArrayStringEditorDialog::OnCustomEditClick
)
2328 // -----------------------------------------------------------------------
2330 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2332 return m_array
[index
];
2335 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2337 return m_array
.size();
2340 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2345 m_array
.Insert(str
,index
);
2349 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2351 m_array
[index
] = str
;
2355 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2357 m_array
.RemoveAt(index
);
2360 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2362 wxString old_str
= m_array
[first
];
2363 wxString new_str
= m_array
[second
];
2364 m_array
[first
] = new_str
;
2365 m_array
[second
] = old_str
;
2368 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2369 : wxArrayEditorDialog()
2374 void wxPGArrayStringEditorDialog::Init()
2376 m_pCallingClass
= NULL
;
2379 void wxPGArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent
& )
2381 wxASSERT( m_pCallingClass
);
2382 wxString str
= m_edValue
->GetValue();
2383 if ( m_pCallingClass
->OnCustomStringEdit(m_parent
,str
) )
2385 //m_edValue->SetValue ( str );
2386 m_lbStrings
->Append ( str
);
2387 m_array
.Add ( str
);
2392 // -----------------------------------------------------------------------
2393 // wxArrayStringProperty
2394 // -----------------------------------------------------------------------
2396 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2397 wxPGProperty
, // Property we inherit from
2398 wxArrayString
, // Value type name
2399 const wxArrayString
&, // Value type, as given in constructor
2400 TextCtrlAndButton
) // Initial editor
2402 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2403 const wxString
& name
,
2404 const wxArrayString
& array
)
2405 : wxPGProperty(label
,name
)
2410 wxArrayStringProperty::~wxArrayStringProperty() { }
2412 void wxArrayStringProperty::OnSetValue()
2414 GenerateValueAsString();
2417 #define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
2418 wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxS('"'),wxS('"'),1)
2420 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2421 int argFlags
) const
2424 // If this is called from GetValueAsString(), return cached string
2425 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2430 wxArrayString arr
= m_value
.GetArrayString();
2432 ARRSTRPROP_ARRAY_TO_STRING(s
, arr
);
2436 // Converts wxArrayString to a string separated by delimeters and spaces.
2437 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2439 void wxPropertyGrid::ArrayStringToString( wxString
& dst
, const wxArrayString
& src
,
2440 wxChar preDelim
, wxChar postDelim
,
2446 unsigned int itemCount
= src
.size();
2448 wxChar preas
[2] = { 0, 0 };
2454 preas
[0] = preDelim
;
2460 dst
.append( preas
);
2462 wxASSERT( postDelim
);
2463 wxString
postDelimStr(postDelim
);
2464 //wxString preDelimStr(preDelim);
2466 for ( i
= 0; i
< itemCount
; i
++ )
2468 wxString
str( src
.Item(i
) );
2470 // Do some character conversion.
2471 // Convertes \ to \\ and <preDelim> to \<preDelim>
2472 // Useful when preDelim and postDelim are "\"".
2475 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2477 str
.Replace( preas
, pdr
, true );
2482 if ( i
< (itemCount
-1) )
2484 dst
.append( postDelimStr
);
2485 dst
.append( wxS(" ") );
2486 dst
.append( preas
);
2488 else if ( preDelim
)
2489 dst
.append( postDelimStr
);
2493 void wxArrayStringProperty::GenerateValueAsString()
2495 wxArrayString arr
= m_value
.GetArrayString();
2496 ARRSTRPROP_ARRAY_TO_STRING(m_display
, arr
);
2499 // Default implementation doesn't do anything.
2500 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2505 wxArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2507 return new wxPGArrayStringEditorDialog();
2510 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2511 wxWindow
* WXUNUSED(primaryCtrl
),
2515 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2517 if ( !propGrid
->EditorValidate() )
2520 // Create editor dialog.
2521 wxArrayEditorDialog
* dlg
= CreateEditorDialog();
2522 #if wxUSE_VALIDATORS
2523 wxValidator
* validator
= GetValidator();
2524 wxPGInDialogValidator dialogValidator
;
2527 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2530 strEdDlg
->SetCustomButton(cbt
, this);
2532 dlg
->SetDialogValue( useValue
);
2533 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2535 #if !wxPG_SMALL_SCREEN
2536 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2545 int res
= dlg
->ShowModal();
2547 if ( res
== wxID_OK
&& dlg
->IsModified() )
2549 wxVariant value
= dlg
->GetDialogValue();
2550 if ( !value
.IsNull() )
2552 wxArrayString actualValue
= value
.GetArrayString();
2554 ARRSTRPROP_ARRAY_TO_STRING(tempStr
, actualValue
);
2555 #if wxUSE_VALIDATORS
2556 if ( dialogValidator
.DoValidate( propGrid
, validator
, tempStr
) )
2559 SetValueInEvent( actualValue
);
2576 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2580 if ( propGrid
->IsMainButtonEvent(event
) )
2581 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2585 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
2589 WX_PG_TOKENIZER2_BEGIN(text
,wxS('"'))
2591 // Need to replace backslashes with empty characters
2592 // (opposite what is done in GenerateValueString).
2593 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2597 WX_PG_TOKENIZER2_END()
2604 // -----------------------------------------------------------------------
2605 // wxPGInDialogValidator
2606 // -----------------------------------------------------------------------
2608 #if wxUSE_VALIDATORS
2609 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2610 wxValidator
* validator
,
2611 const wxString
& value
)
2616 wxTextCtrl
* tc
= m_textCtrl
;
2621 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2622 wxPoint(30000,30000));
2629 tc
->SetValue(value
);
2631 validator
->SetWindow(tc
);
2632 bool res
= validator
->Validate(propGrid
);
2637 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2638 wxValidator
* WXUNUSED(validator
),
2639 const wxString
& WXUNUSED(value
) )
2645 // -----------------------------------------------------------------------
2647 #endif // wxUSE_PROPGRID