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 // -----------------------------------------------------------------------
147 // -----------------------------------------------------------------------
149 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxIntProperty
,wxPGProperty
,
152 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
153 long value
) : wxPGProperty(label
,name
)
158 wxIntProperty::wxIntProperty( const wxString
& label
, const wxString
& name
,
159 const wxLongLong
& value
) : wxPGProperty(label
,name
)
161 SetValue(WXVARIANT(value
));
164 wxIntProperty::~wxIntProperty() { }
166 wxString
wxIntProperty::ValueToString( wxVariant
& value
,
167 int WXUNUSED(argFlags
) ) const
169 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
171 return wxString::Format(wxS("%li"),value
.GetLong());
173 else if ( value
.GetType() == wxPG_VARIANT_TYPE_LONGLONG
)
175 wxLongLong ll
= value
.GetLongLong();
176 return ll
.ToString();
179 return wxEmptyString
;
182 bool wxIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
187 if ( text
.length() == 0 )
193 // We know it is a number, but let's still check
195 if ( text
.IsNumber() )
197 // Remove leading zeroes, so that the number is not interpreted as octal
198 wxString::const_iterator i
= text
.begin();
199 wxString::const_iterator iMax
= text
.end() - 1; // Let's allow one, last zero though
201 int firstNonZeroPos
= 0;
203 for ( ; i
!= iMax
; ++i
)
206 if ( c
!= wxS('0') && c
!= wxS(' ') )
211 wxString useText
= text
.substr(firstNonZeroPos
, text
.length() - firstNonZeroPos
);
213 wxString variantType
= variant
.GetType();
214 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
216 wxLongLong_t value64
= 0;
218 if ( useText
.ToLongLong(&value64
, 10) &&
219 ( value64
>= INT_MAX
|| value64
<= INT_MIN
)
222 bool doChangeValue
= isPrevLong
;
224 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_LONGLONG
)
226 wxLongLong oldValue
= variant
.GetLongLong();
227 if ( oldValue
.GetValue() != value64
)
228 doChangeValue
= true;
233 wxLongLong
ll(value64
);
239 if ( useText
.ToLong( &value32
, 0 ) )
241 if ( !isPrevLong
|| variant
!= value32
)
248 else if ( argFlags
& wxPG_REPORT_ERROR
)
254 bool wxIntProperty::IntToValue( wxVariant
& variant
, int value
, int WXUNUSED(argFlags
) ) const
256 if ( variant
.GetType() != wxPG_VARIANT_TYPE_LONG
|| variant
!= (long)value
)
258 variant
= (long)value
;
264 bool wxIntProperty::DoValidation( const wxPGProperty
* property
, wxLongLong_t
& value
, wxPGValidationInfo
* pValidationInfo
, int mode
)
267 wxLongLong_t min
= wxINT64_MIN
;
268 wxLongLong_t max
= wxINT64_MAX
;
273 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
274 if ( !variant
.IsNull() )
276 min
= variant
.GetLongLong().GetValue();
280 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
281 if ( !variant
.IsNull() )
283 max
= variant
.GetLongLong().GetValue();
291 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
295 msg
= wxString::Format(
296 _("Value must be %lld or higher."), min
);
298 msg
= wxString::Format(
299 _("Value must be between %lld and %lld."),
301 pValidationInfo
->SetFailureMessage(msg
);
303 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
306 value
= max
- (min
- value
);
315 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
319 msg
= wxString::Format(
320 _("Value must be %lld or lower."), max
);
322 msg
= wxString::Format(
323 _("Value must be between %lld and %lld."),
325 pValidationInfo
->SetFailureMessage(msg
);
327 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
330 value
= min
+ (value
- max
);
337 bool wxIntProperty::ValidateValue( wxVariant
& value
,
338 wxPGValidationInfo
& validationInfo
) const
340 wxLongLong_t ll
= value
.GetLongLong().GetValue();
341 return DoValidation(this, ll
, &validationInfo
,
342 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
345 wxValidator
* wxIntProperty::GetClassValidator()
348 WX_PG_DOGETVALIDATOR_ENTRY()
350 // Atleast wxPython 2.6.2.1 required that the string argument is given
352 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_NUMERIC
,&v
);
354 WX_PG_DOGETVALIDATOR_EXIT(validator
)
360 wxValidator
* wxIntProperty::DoGetValidator() const
362 return GetClassValidator();
365 // -----------------------------------------------------------------------
367 // -----------------------------------------------------------------------
370 #define wxPG_UINT_TEMPLATE_MAX 8
372 static const wxChar
* const gs_uintTemplates32
[wxPG_UINT_TEMPLATE_MAX
] = {
373 wxT("%x"),wxT("0x%x"),wxT("$%x"),
374 wxT("%X"),wxT("0x%X"),wxT("$%X"),
378 static const char* const gs_uintTemplates64
[wxPG_UINT_TEMPLATE_MAX
] = {
379 "%" wxLongLongFmtSpec
"x",
380 "0x%" wxLongLongFmtSpec
"x",
381 "$%" wxLongLongFmtSpec
"x",
382 "%" wxLongLongFmtSpec
"X",
383 "0x%" wxLongLongFmtSpec
"X",
384 "$%" wxLongLongFmtSpec
"X",
385 "%" wxLongLongFmtSpec
"u",
386 "%" wxLongLongFmtSpec
"o"
389 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty
,wxPGProperty
,
390 long,unsigned long,TextCtrl
)
392 void wxUIntProperty::Init()
394 m_base
= 6; // This is magic number for dec base (must be same as in setattribute)
396 m_prefix
= wxPG_PREFIX_NONE
;
399 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
400 unsigned long value
) : wxPGProperty(label
,name
)
403 SetValue((long)value
);
406 wxUIntProperty::wxUIntProperty( const wxString
& label
, const wxString
& name
,
407 const wxULongLong
& value
) : wxPGProperty(label
,name
)
410 SetValue(WXVARIANT(value
));
413 wxUIntProperty::~wxUIntProperty() { }
415 wxString
wxUIntProperty::ValueToString( wxVariant
& value
,
416 int WXUNUSED(argFlags
) ) const
418 size_t index
= m_base
+ m_prefix
;
419 if ( index
>= wxPG_UINT_TEMPLATE_MAX
)
420 index
= wxPG_BASE_DEC
;
422 if ( value
.GetType() == wxPG_VARIANT_TYPE_LONG
)
424 return wxString::Format(gs_uintTemplates32
[index
],
425 (unsigned long)value
.GetLong());
428 wxULongLong ull
= value
.GetULongLong();
430 return wxString::Format(gs_uintTemplates64
[index
], ull
.GetValue());
433 bool wxUIntProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
435 wxString variantType
= variant
.GetType();
436 bool isPrevLong
= variantType
== wxPG_VARIANT_TYPE_LONG
;
438 if ( text
.length() == 0 )
445 if ( text
[0] == wxS('$') )
448 wxULongLong_t value64
= 0;
449 wxString s
= text
.substr(start
, text
.length() - start
);
451 if ( s
.ToULongLong(&value64
, (unsigned int)m_realBase
) )
453 if ( value64
>= LONG_MAX
)
455 bool doChangeValue
= isPrevLong
;
457 if ( !isPrevLong
&& variantType
== wxPG_VARIANT_TYPE_ULONGLONG
)
459 wxULongLong oldValue
= variant
.GetULongLong();
460 if ( oldValue
.GetValue() != value64
)
461 doChangeValue
= true;
466 variant
= wxULongLong(value64
);
472 unsigned long value32
= wxLongLong(value64
).GetLo();
473 if ( !isPrevLong
|| m_value
!= (long)value32
)
475 variant
= (long)value32
;
484 bool wxUIntProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
486 if ( variant
!= (long)number
)
488 variant
= (long)number
;
494 bool wxUIntProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& validationInfo
) const
497 wxULongLong_t ll
= value
.GetULongLong().GetValue();
499 wxULongLong_t min
= 0;
500 wxULongLong_t max
= wxUINT64_MAX
;
503 variant
= GetAttribute(wxPGGlobalVars
->m_strMin
);
504 if ( !variant
.IsNull() )
506 min
= variant
.GetULongLong().GetValue();
509 validationInfo
.SetFailureMessage(
510 wxString::Format(_("Value must be %llu or higher"),min
)
515 variant
= GetAttribute(wxPGGlobalVars
->m_strMax
);
516 if ( !variant
.IsNull() )
518 max
= variant
.GetULongLong().GetValue();
521 validationInfo
.SetFailureMessage(
522 wxString::Format(_("Value must be %llu or less"),max
)
531 bool wxUIntProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
533 if ( name
== wxPG_UINT_BASE
)
535 int val
= value
.GetLong();
537 m_realBase
= (wxByte
) val
;
538 if ( m_realBase
> 16 )
542 // Translate logical base to a template array index
544 if ( val
== wxPG_BASE_HEX
)
546 else if ( val
== wxPG_BASE_DEC
)
548 else if ( val
== wxPG_BASE_HEXL
)
552 else if ( name
== wxPG_UINT_PREFIX
)
554 m_prefix
= (wxByte
) value
.GetLong();
560 // -----------------------------------------------------------------------
562 // -----------------------------------------------------------------------
564 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFloatProperty
,wxPGProperty
,
565 double,double,TextCtrl
)
567 wxFloatProperty::wxFloatProperty( const wxString
& label
,
568 const wxString
& name
,
570 : wxPGProperty(label
,name
)
576 wxFloatProperty::~wxFloatProperty() { }
578 // This helper method provides standard way for floating point-using
579 // properties to convert values to string.
580 void wxPropertyGrid::DoubleToString(wxString
& target
,
584 wxString
* precTemplate
)
586 if ( precision
>= 0 )
590 precTemplate
= &text1
;
592 if ( !precTemplate
->length() )
594 *precTemplate
= wxS("%.");
595 *precTemplate
<< wxString::Format( wxS("%i"), precision
);
596 *precTemplate
<< wxS('f');
599 target
.Printf( precTemplate
->c_str(), value
);
603 target
.Printf( wxS("%f"), value
);
606 if ( removeZeroes
&& precision
!= 0 && target
.length() )
608 // Remove excess zeroes (do not remove this code just yet,
609 // since sprintf can't do the same consistently across platforms).
610 wxString::const_iterator i
= target
.end() - 1;
611 size_t new_len
= target
.length() - 1;
613 for ( ; i
!= target
.begin(); --i
)
615 if ( *i
!= wxS('0') )
620 wxChar cur_char
= *i
;
621 if ( cur_char
!= wxS('.') && cur_char
!= wxS(',') )
624 if ( new_len
!= target
.length() )
625 target
.resize(new_len
);
629 wxString
wxFloatProperty::ValueToString( wxVariant
& value
,
633 if ( !value
.IsNull() )
635 wxPropertyGrid::DoubleToString(text
,
638 !(argFlags
& wxPG_FULL_VALUE
),
644 bool wxFloatProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
649 if ( text
.length() == 0 )
655 bool res
= text
.ToDouble(&value
);
658 if ( variant
!= value
)
664 else if ( argFlags
& wxPG_REPORT_ERROR
)
670 bool wxFloatProperty::DoValidation( const wxPGProperty
* property
,
672 wxPGValidationInfo
* pValidationInfo
,
676 double min
= (double)wxINT64_MIN
;
677 double max
= (double)wxINT64_MAX
;
682 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMin
);
683 if ( !variant
.IsNull() )
685 min
= variant
.GetDouble();
689 variant
= property
->GetAttribute(wxPGGlobalVars
->m_strMax
);
690 if ( !variant
.IsNull() )
692 max
= variant
.GetDouble();
700 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
701 pValidationInfo
->SetFailureMessage(
702 wxString::Format(_("Value must be %f or higher"),min
)
704 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
707 value
= max
- (min
- value
);
714 max
= variant
.GetDouble();
717 if ( mode
== wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
)
718 pValidationInfo
->SetFailureMessage(
719 wxString::Format(_("Value must be %f or less"),max
)
721 else if ( mode
== wxPG_PROPERTY_VALIDATION_SATURATE
)
724 value
= min
+ (value
- max
);
732 wxFloatProperty::ValidateValue( wxVariant
& value
,
733 wxPGValidationInfo
& validationInfo
) const
735 double fpv
= value
.GetDouble();
736 return DoValidation(this, fpv
, &validationInfo
,
737 wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE
);
740 bool wxFloatProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
742 if ( name
== wxPG_FLOAT_PRECISION
)
744 m_precision
= value
.GetLong();
750 wxValidator
* wxFloatProperty::DoGetValidator() const
752 return wxIntProperty::GetClassValidator();
755 // -----------------------------------------------------------------------
757 // -----------------------------------------------------------------------
759 // We cannot use standard WX_PG_IMPLEMENT_PROPERTY_CLASS macro, since
760 // there is a custom GetEditorClass.
762 IMPLEMENT_DYNAMIC_CLASS(wxBoolProperty
, wxPGProperty
)
764 const wxPGEditor
* wxBoolProperty::DoGetEditorClass() const
766 // Select correct editor control.
767 #if wxPG_INCLUDE_CHECKBOX
768 if ( !(m_flags
& wxPG_PROP_USE_CHECKBOX
) )
769 return wxPGEditor_Choice
;
770 return wxPGEditor_CheckBox
;
772 return wxPGEditor_Choice
;
776 wxBoolProperty::wxBoolProperty( const wxString
& label
, const wxString
& name
, bool value
) :
777 wxPGProperty(label
,name
)
779 m_choices
.Assign(wxPGGlobalVars
->m_boolChoices
);
781 SetValue(wxPGVariant_Bool(value
));
783 m_flags
|= wxPG_PROP_USE_DCC
;
786 wxBoolProperty::~wxBoolProperty() { }
788 wxString
wxBoolProperty::ValueToString( wxVariant
& value
,
791 bool boolValue
= value
.GetBool();
793 // As a fragment of composite string value,
794 // make it a little more readable.
795 if ( argFlags
& wxPG_COMPOSITE_FRAGMENT
)
803 if ( argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
)
804 return wxEmptyString
;
807 if ( wxPGGlobalVars
->m_autoGetTranslation
)
808 notFmt
= _("Not %s");
810 notFmt
= wxS("Not %s");
812 return wxString::Format(notFmt
.c_str(), m_label
.c_str());
816 if ( !(argFlags
& wxPG_FULL_VALUE
) )
818 return wxPGGlobalVars
->m_boolChoices
[boolValue
?1:0].GetText();
823 if ( boolValue
) text
= wxS("true");
824 else text
= wxS("false");
829 bool wxBoolProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int WXUNUSED(argFlags
) ) const
831 bool boolValue
= false;
832 if ( text
.CmpNoCase(wxPGGlobalVars
->m_boolChoices
[1].GetText()) == 0 ||
833 text
.CmpNoCase(wxS("true")) == 0 ||
834 text
.CmpNoCase(m_label
) == 0 )
837 if ( text
.length() == 0 )
843 if ( variant
!= boolValue
)
845 variant
= wxPGVariant_Bool(boolValue
);
851 bool wxBoolProperty::IntToValue( wxVariant
& variant
, int value
, int ) const
853 bool boolValue
= value
? true : false;
855 if ( variant
!= boolValue
)
857 variant
= wxPGVariant_Bool(boolValue
);
863 bool wxBoolProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
865 #if wxPG_INCLUDE_CHECKBOX
866 if ( name
== wxPG_BOOL_USE_CHECKBOX
)
868 if ( value
.GetLong() )
869 m_flags
|= wxPG_PROP_USE_CHECKBOX
;
871 m_flags
&= ~(wxPG_PROP_USE_CHECKBOX
);
875 if ( name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
877 if ( value
.GetLong() )
878 m_flags
|= wxPG_PROP_USE_DCC
;
880 m_flags
&= ~(wxPG_PROP_USE_DCC
);
886 // -----------------------------------------------------------------------
888 // -----------------------------------------------------------------------
890 IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty
, wxPGProperty
)
892 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty
,long,Choice
)
894 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
895 const long* values
, int value
) : wxPGProperty(label
,name
)
901 m_choices
.Add(labels
,values
);
903 if ( GetItemCount() )
904 SetValue( (long)value
);
908 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
909 const long* values
, wxPGChoices
* choicesCache
, int value
)
910 : wxPGProperty(label
,name
)
914 wxASSERT( choicesCache
);
916 if ( choicesCache
->IsOk() )
918 m_choices
.Assign( *choicesCache
);
919 m_value
= wxPGVariant_Zero
;
923 m_choices
.Add(labels
,values
);
925 if ( GetItemCount() )
926 SetValue( (long)value
);
930 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
931 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
932 : wxPGProperty(label
,name
)
936 if ( &labels
&& labels
.size() )
938 m_choices
.Set(labels
, values
);
940 if ( GetItemCount() )
941 SetValue( (long)value
);
945 wxEnumProperty::wxEnumProperty( const wxString
& label
, const wxString
& name
,
946 wxPGChoices
& choices
, int value
)
947 : wxPGProperty(label
,name
)
949 m_choices
.Assign( choices
);
951 if ( GetItemCount() )
952 SetValue( (long)value
);
955 int wxEnumProperty::GetIndexForValue( int value
) const
957 if ( !m_choices
.IsOk() )
960 int intVal
= m_choices
.Index(value
);
967 wxEnumProperty::~wxEnumProperty ()
971 int wxEnumProperty::ms_nextIndex
= -2;
973 void wxEnumProperty::OnSetValue()
975 wxString variantType
= m_value
.GetType();
977 if ( variantType
== wxPG_VARIANT_TYPE_LONG
)
979 ValueFromInt_( m_value
, m_value
.GetLong(), wxPG_FULL_VALUE
);
981 else if ( variantType
== wxPG_VARIANT_TYPE_STRING
)
983 ValueFromString_( m_value
, m_value
.GetString(), 0 );
990 if ( ms_nextIndex
!= -2 )
992 m_index
= ms_nextIndex
;
997 bool wxEnumProperty::ValidateValue( wxVariant
& value
, wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
999 // Make sure string value is in the list,
1000 // unless property has string as preferred value type
1001 // To reduce code size, use conversion here as well
1002 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
&&
1003 !this->IsKindOf(CLASSINFO(wxEditEnumProperty
)) )
1004 return ValueFromString_( value
, value
.GetString(), wxPG_PROPERTY_SPECIFIC
);
1009 wxString
wxEnumProperty::ValueToString( wxVariant
& value
,
1010 int WXUNUSED(argFlags
) ) const
1012 if ( value
.GetType() == wxPG_VARIANT_TYPE_STRING
)
1013 return value
.GetString();
1015 int index
= m_choices
.Index(value
.GetLong());
1017 return wxEmptyString
;
1019 return m_choices
.GetLabel(index
);
1022 bool wxEnumProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1024 return ValueFromString_( variant
, text
, argFlags
);
1027 bool wxEnumProperty::IntToValue( wxVariant
& variant
, int intVal
, int argFlags
) const
1029 return ValueFromInt_( variant
, intVal
, argFlags
);
1032 bool wxEnumProperty::ValueFromString_( wxVariant
& value
, const wxString
& text
, int argFlags
) const
1037 for ( unsigned int i
=0; i
<m_choices
.GetCount(); i
++ )
1039 const wxString
& entryLabel
= m_choices
.GetLabel(i
);
1040 if ( text
.CmpNoCase(entryLabel
) == 0 )
1043 useValue
= m_choices
.GetValue(i
);
1048 bool asText
= false;
1050 bool isEdit
= this->IsKindOf(CLASSINFO(wxEditEnumProperty
));
1052 // If text not any of the choices, store as text instead
1053 // (but only if we are wxEditEnumProperty)
1054 if ( useIndex
== -1 && isEdit
)
1059 int setAsNextIndex
= -2;
1063 setAsNextIndex
= -1;
1066 else if ( useIndex
!= GetIndex() )
1068 if ( useIndex
!= -1 )
1070 setAsNextIndex
= useIndex
;
1071 value
= (long)useValue
;
1075 setAsNextIndex
= -1;
1076 value
= wxPGVariant_MinusOne
;
1080 if ( setAsNextIndex
!= -2 )
1082 // If wxPG_PROPERTY_SPECIFIC is set, then this is done for
1083 // validation purposes only, and index must not be changed
1084 if ( !(argFlags
& wxPG_PROPERTY_SPECIFIC
) )
1085 ms_nextIndex
= setAsNextIndex
;
1087 if ( isEdit
|| setAsNextIndex
!= -1 )
1095 bool wxEnumProperty::ValueFromInt_( wxVariant
& variant
, int intVal
, int argFlags
) const
1097 // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
1101 if ( argFlags
& wxPG_FULL_VALUE
)
1103 ms_nextIndex
= GetIndexForValue( intVal
);
1107 if ( intVal
!= GetIndex() )
1109 ms_nextIndex
= intVal
;
1113 if ( ms_nextIndex
!= -2 )
1115 if ( !(argFlags
& wxPG_FULL_VALUE
) )
1116 intVal
= m_choices
.GetValue(intVal
);
1118 variant
= (long)intVal
;
1127 wxEnumProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
1133 void wxEnumProperty::SetIndex( int index
)
1139 int wxEnumProperty::GetIndex() const
1141 if ( m_value
.IsNull() )
1144 if ( ms_nextIndex
!= -2 )
1145 return ms_nextIndex
;
1150 // -----------------------------------------------------------------------
1151 // wxEditEnumProperty
1152 // -----------------------------------------------------------------------
1154 IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty
, wxPGProperty
)
1156 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty
,wxString
,ComboBox
)
1158 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1159 const long* values
, const wxString
& value
)
1160 : wxEnumProperty(label
,name
,labels
,values
,0)
1165 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
, const wxChar
* const* labels
,
1166 const long* values
, wxPGChoices
* choicesCache
, const wxString
& value
)
1167 : wxEnumProperty(label
,name
,labels
,values
,choicesCache
,0)
1172 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1173 const wxArrayString
& labels
, const wxArrayInt
& values
, const wxString
& value
)
1174 : wxEnumProperty(label
,name
,labels
,values
,0)
1179 wxEditEnumProperty::wxEditEnumProperty( const wxString
& label
, const wxString
& name
,
1180 wxPGChoices
& choices
, const wxString
& value
)
1181 : wxEnumProperty(label
,name
,choices
,0)
1186 wxEditEnumProperty::~wxEditEnumProperty()
1190 // -----------------------------------------------------------------------
1192 // -----------------------------------------------------------------------
1194 IMPLEMENT_DYNAMIC_CLASS(wxFlagsProperty
,wxPGProperty
)
1196 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty
,long,TextCtrl
)
1198 void wxFlagsProperty::Init()
1200 long value
= m_value
;
1203 // Generate children
1207 unsigned int prevChildCount
= m_children
.size();
1210 if ( prevChildCount
)
1212 wxPropertyGridPageState
* state
= GetParentState();
1214 // State safety check (it may be NULL in immediate parent)
1219 wxPGProperty
* selected
= state
->GetSelection();
1222 if ( selected
->GetParent() == this )
1223 oldSel
= selected
->GetIndexInParent();
1224 else if ( selected
== this )
1228 state
->DoClearSelection();
1231 // Delete old children
1232 for ( i
=0; i
<prevChildCount
; i
++ )
1233 delete m_children
[i
];
1237 // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
1238 // to child bool property controls.
1239 long attrUseCheckBox
= GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX
, 0);
1240 long attrUseDCC
= GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1243 if ( m_choices
.IsOk() )
1245 const wxPGChoices
& choices
= m_choices
;
1247 for ( i
=0; i
<GetItemCount(); i
++ )
1250 child_val
= ( value
& choices
.GetValue(i
) )?true:false;
1252 wxPGProperty
* boolProp
;
1253 wxString label
= GetLabel(i
);
1256 if ( wxPGGlobalVars
->m_autoGetTranslation
)
1258 boolProp
= new wxBoolProperty( ::wxGetTranslation(label
), label
, child_val
);
1263 boolProp
= new wxBoolProperty( label
, label
, child_val
);
1265 if ( attrUseCheckBox
)
1266 boolProp
->SetAttribute(wxPG_BOOL_USE_CHECKBOX
,
1269 boolProp
->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
,
1271 AddPrivateChild(boolProp
);
1274 m_oldChoicesData
= m_choices
.GetDataPtr();
1277 m_oldValue
= m_value
;
1279 if ( prevChildCount
)
1280 SubPropsChanged(oldSel
);
1283 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1284 const wxChar
* const* labels
, const long* values
, long value
) : wxPGProperty(label
,name
)
1286 m_oldChoicesData
= NULL
;
1290 m_choices
.Set(labels
,values
);
1292 wxASSERT( GetItemCount() );
1298 m_value
= wxPGVariant_Zero
;
1302 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1303 const wxArrayString
& labels
, const wxArrayInt
& values
, int value
)
1304 : wxPGProperty(label
,name
)
1306 m_oldChoicesData
= NULL
;
1308 if ( &labels
&& labels
.size() )
1310 m_choices
.Set(labels
,values
);
1312 wxASSERT( GetItemCount() );
1314 SetValue( (long)value
);
1318 m_value
= wxPGVariant_Zero
;
1322 wxFlagsProperty::wxFlagsProperty( const wxString
& label
, const wxString
& name
,
1323 wxPGChoices
& choices
, long value
)
1324 : wxPGProperty(label
,name
)
1326 m_oldChoicesData
= NULL
;
1328 if ( choices
.IsOk() )
1330 m_choices
.Assign(choices
);
1332 wxASSERT( GetItemCount() );
1338 m_value
= wxPGVariant_Zero
;
1342 wxFlagsProperty::~wxFlagsProperty()
1346 void wxFlagsProperty::OnSetValue()
1348 if ( !m_choices
.IsOk() || !GetItemCount() )
1350 m_value
= wxPGVariant_Zero
;
1354 long val
= m_value
.GetLong();
1358 // normalize the value (i.e. remove extra flags)
1360 const wxPGChoices
& choices
= m_choices
;
1361 for ( i
= 0; i
< GetItemCount(); i
++ )
1363 fullFlags
|= choices
.GetValue(i
);
1370 // Need to (re)init now?
1371 if ( GetChildCount() != GetItemCount() ||
1372 m_choices
.GetDataPtr() != m_oldChoicesData
)
1378 long newFlags
= m_value
;
1380 if ( newFlags
!= m_oldValue
)
1382 // Set child modified states
1384 const wxPGChoices
& choices
= m_choices
;
1385 for ( i
= 0; i
<GetItemCount(); i
++ )
1389 flag
= choices
.GetValue(i
);
1391 if ( (newFlags
& flag
) != (m_oldValue
& flag
) )
1392 Item(i
)->SetFlag( wxPG_PROP_MODIFIED
);
1395 m_oldValue
= newFlags
;
1399 wxString
wxFlagsProperty::ValueToString( wxVariant
& value
,
1400 int WXUNUSED(argFlags
) ) const
1404 if ( !m_choices
.IsOk() )
1409 const wxPGChoices
& choices
= m_choices
;
1411 for ( i
= 0; i
< GetItemCount(); i
++ )
1414 doAdd
= ( flags
& choices
.GetValue(i
) );
1418 text
+= choices
.GetLabel(i
);
1423 // remove last comma
1424 if ( text
.Len() > 1 )
1425 text
.Truncate ( text
.Len() - 2 );
1430 // Translate string into flag tokens
1431 bool wxFlagsProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1433 if ( !m_choices
.IsOk() )
1438 // semicolons are no longer valid delimeters
1439 WX_PG_TOKENIZER1_BEGIN(text
,wxS(','))
1441 if ( token
.length() )
1443 // Determine which one it is
1444 long bit
= IdToBit( token
);
1457 WX_PG_TOKENIZER1_END()
1459 if ( variant
!= (long)newFlags
)
1461 variant
= (long)newFlags
;
1468 // Converts string id to a relevant bit.
1469 long wxFlagsProperty::IdToBit( const wxString
& id
) const
1472 for ( i
= 0; i
< GetItemCount(); i
++ )
1474 if ( id
== GetLabel(i
) )
1476 return m_choices
.GetValue(i
);
1482 void wxFlagsProperty::RefreshChildren()
1484 if ( !m_choices
.IsOk() || !GetChildCount() ) return;
1486 int flags
= m_value
.GetLong();
1488 const wxPGChoices
& choices
= m_choices
;
1490 for ( i
= 0; i
< GetItemCount(); i
++ )
1494 flag
= choices
.GetValue(i
);
1496 long subVal
= flags
& flag
;
1497 wxPGProperty
* p
= Item(i
);
1499 if ( subVal
!= (m_oldValue
& flag
) )
1500 p
->SetFlag( wxPG_PROP_MODIFIED
);
1502 p
->SetValue( subVal
?true:false );
1508 wxVariant
wxFlagsProperty::ChildChanged( wxVariant
& thisValue
,
1510 wxVariant
& childValue
) const
1512 long oldValue
= thisValue
.GetLong();
1513 long val
= childValue
.GetLong();
1514 unsigned long vi
= m_choices
.GetValue(childIndex
);
1517 return (long) (oldValue
| vi
);
1519 return (long) (oldValue
& ~(vi
));
1522 bool wxFlagsProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1524 if ( name
== wxPG_BOOL_USE_CHECKBOX
||
1525 name
== wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
)
1527 for ( size_t i
=0; i
<GetChildCount(); i
++ )
1529 Item(i
)->SetAttribute(name
, value
);
1531 // Must return false so that the attribute is stored in
1532 // flag property's actual property storage
1538 // -----------------------------------------------------------------------
1540 // -----------------------------------------------------------------------
1542 IMPLEMENT_DYNAMIC_CLASS(wxDirProperty
, wxLongStringProperty
)
1544 wxDirProperty::wxDirProperty( const wxString
& name
, const wxString
& label
, const wxString
& value
)
1545 : wxLongStringProperty(name
,label
,value
)
1547 m_flags
|= wxPG_PROP_NO_ESCAPE
;
1550 wxDirProperty::~wxDirProperty() { }
1552 wxValidator
* wxDirProperty::DoGetValidator() const
1554 return wxFileProperty::GetClassValidator();
1557 bool wxDirProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1559 // Update property value from editor, if necessary
1560 wxSize
dlg_sz(300,400);
1562 wxString
dlgMessage(m_dlgMessage
);
1563 if ( dlgMessage
.empty() )
1564 dlgMessage
= _("Choose a directory:");
1565 wxDirDialog
dlg( propGrid
,
1569 #if !wxPG_SMALL_SCREEN
1570 propGrid
->GetGoodEditorDialogPosition(this,dlg_sz
),
1578 if ( dlg
.ShowModal() == wxID_OK
)
1580 value
= dlg
.GetPath();
1586 bool wxDirProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1588 if ( name
== wxPG_DIR_DIALOG_MESSAGE
)
1590 m_dlgMessage
= value
.GetString();
1596 // -----------------------------------------------------------------------
1597 // wxPGFileDialogAdapter
1598 // -----------------------------------------------------------------------
1600 bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1602 wxFileProperty
* fileProp
= NULL
;
1606 if ( property
->IsKindOf(CLASSINFO(wxFileProperty
)) )
1608 fileProp
= ((wxFileProperty
*)property
);
1609 wxFileName filename
= fileProp
->GetValue().GetString();
1610 path
= filename
.GetPath();
1611 indFilter
= fileProp
->m_indFilter
;
1613 if ( !path
.length() && fileProp
->m_basePath
.length() )
1614 path
= fileProp
->m_basePath
;
1618 wxFileName
fn(property
->GetValue().GetString());
1619 path
= fn
.GetPath();
1622 wxFileDialog
dlg( propGrid
->GetPanel(),
1623 property
->GetAttribute(wxS("DialogTitle"), _("Choose a file")),
1624 property
->GetAttribute(wxS("InitialPath"), path
),
1626 property
->GetAttribute(wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*")),
1628 wxDefaultPosition
);
1630 if ( indFilter
>= 0 )
1631 dlg
.SetFilterIndex( indFilter
);
1633 if ( dlg
.ShowModal() == wxID_OK
)
1636 fileProp
->m_indFilter
= dlg
.GetFilterIndex();
1637 SetValue( dlg
.GetPath() );
1643 // -----------------------------------------------------------------------
1645 // -----------------------------------------------------------------------
1647 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFileProperty
,wxPGProperty
,
1648 wxString
,const wxString
&,TextCtrlAndButton
)
1650 wxFileProperty::wxFileProperty( const wxString
& label
, const wxString
& name
,
1651 const wxString
& value
) : wxPGProperty(label
,name
)
1653 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1655 SetAttribute( wxPG_FILE_WILDCARD
, _("All files (*.*)|*.*") );
1660 wxFileProperty::~wxFileProperty() {}
1662 wxValidator
* wxFileProperty::GetClassValidator()
1664 #if wxUSE_VALIDATORS
1665 WX_PG_DOGETVALIDATOR_ENTRY()
1667 // Atleast wxPython 2.6.2.1 required that the string argument is given
1669 wxTextValidator
* validator
= new wxTextValidator(wxFILTER_EXCLUDE_CHAR_LIST
,&v
);
1671 wxArrayString exChars
;
1672 exChars
.Add(wxS("?"));
1673 exChars
.Add(wxS("*"));
1674 exChars
.Add(wxS("|"));
1675 exChars
.Add(wxS("<"));
1676 exChars
.Add(wxS(">"));
1677 exChars
.Add(wxS("\""));
1679 validator
->SetExcludes(exChars
);
1681 WX_PG_DOGETVALIDATOR_EXIT(validator
)
1687 wxValidator
* wxFileProperty::DoGetValidator() const
1689 return GetClassValidator();
1692 void wxFileProperty::OnSetValue()
1694 const wxString
& fnstr
= m_value
.GetString();
1696 wxFileName filename
= fnstr
;
1698 if ( !filename
.HasName() )
1700 m_value
= wxPGVariant_EmptyString
;
1703 // Find index for extension.
1704 if ( m_indFilter
< 0 && fnstr
.length() )
1706 wxString ext
= filename
.GetExt();
1709 size_t len
= m_wildcard
.length();
1711 pos
= m_wildcard
.find(wxS("|"), pos
);
1712 while ( pos
!= wxString::npos
&& pos
< (len
-3) )
1714 size_t ext_begin
= pos
+ 3;
1716 pos
= m_wildcard
.find(wxS("|"), ext_begin
);
1717 if ( pos
== wxString::npos
)
1719 wxString found_ext
= m_wildcard
.substr(ext_begin
, pos
-ext_begin
);
1721 if ( found_ext
.length() > 0 )
1723 if ( found_ext
[0] == wxS('*') )
1725 m_indFilter
= curind
;
1728 if ( ext
.CmpNoCase(found_ext
) == 0 )
1730 m_indFilter
= curind
;
1736 pos
= m_wildcard
.find(wxS("|"), pos
+1);
1743 wxFileName
wxFileProperty::GetFileName() const
1745 wxFileName filename
;
1747 if ( !m_value
.IsNull() )
1748 filename
= m_value
.GetString();
1753 wxString
wxFileProperty::ValueToString( wxVariant
& value
,
1754 int argFlags
) const
1756 wxFileName filename
= value
.GetString();
1758 if ( !filename
.HasName() )
1759 return wxEmptyString
;
1761 wxString fullName
= filename
.GetFullName();
1762 if ( !fullName
.length() )
1763 return wxEmptyString
;
1765 if ( argFlags
& wxPG_FULL_VALUE
)
1767 return filename
.GetFullPath();
1769 else if ( m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
)
1771 if ( m_basePath
.Length() )
1773 wxFileName
fn2(filename
);
1774 fn2
.MakeRelativeTo(m_basePath
);
1775 return fn2
.GetFullPath();
1777 return filename
.GetFullPath();
1780 return filename
.GetFullName();
1783 wxPGEditorDialogAdapter
* wxFileProperty::GetEditorDialog() const
1785 return new wxPGFileDialogAdapter();
1788 bool wxFileProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
1790 wxFileName filename
= variant
.GetString();
1792 if ( (m_flags
& wxPG_PROP_SHOW_FULL_FILENAME
) || (argFlags
& wxPG_FULL_VALUE
) )
1794 if ( filename
!= text
)
1802 if ( filename
.GetFullName() != text
)
1804 wxFileName fn
= filename
;
1805 fn
.SetFullName(text
);
1806 variant
= fn
.GetFullPath();
1814 bool wxFileProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
1816 // Return false on some occasions to make sure those attribs will get
1817 // stored in m_attributes.
1818 if ( name
== wxPG_FILE_SHOW_FULL_PATH
)
1820 if ( value
.GetLong() )
1821 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1823 m_flags
&= ~(wxPG_PROP_SHOW_FULL_FILENAME
);
1826 else if ( name
== wxPG_FILE_WILDCARD
)
1828 m_wildcard
= value
.GetString();
1830 else if ( name
== wxPG_FILE_SHOW_RELATIVE_PATH
)
1832 m_basePath
= value
.GetString();
1834 // Make sure wxPG_FILE_SHOW_FULL_PATH is also set
1835 m_flags
|= wxPG_PROP_SHOW_FULL_FILENAME
;
1837 else if ( name
== wxPG_FILE_INITIAL_PATH
)
1839 m_initialPath
= value
.GetString();
1842 else if ( name
== wxPG_FILE_DIALOG_TITLE
)
1844 m_dlgTitle
= value
.GetString();
1850 // -----------------------------------------------------------------------
1851 // wxPGLongStringDialogAdapter
1852 // -----------------------------------------------------------------------
1854 bool wxPGLongStringDialogAdapter::DoShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1856 wxString val1
= property
->GetValueAsString(0);
1857 wxString val_orig
= val1
;
1860 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1861 wxPropertyGrid::ExpandEscapeSequences(value
, val1
);
1863 value
= wxString(val1
);
1865 // Run editor dialog.
1866 if ( wxLongStringProperty::DisplayEditorDialog(property
, propGrid
, value
) )
1868 if ( !property
->HasFlag(wxPG_PROP_NO_ESCAPE
) )
1869 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1873 if ( val1
!= val_orig
)
1882 // -----------------------------------------------------------------------
1883 // wxLongStringProperty
1884 // -----------------------------------------------------------------------
1886 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxLongStringProperty
,wxPGProperty
,
1887 wxString
,const wxString
&,TextCtrlAndButton
)
1889 wxLongStringProperty::wxLongStringProperty( const wxString
& label
, const wxString
& name
,
1890 const wxString
& value
) : wxPGProperty(label
,name
)
1895 wxLongStringProperty::~wxLongStringProperty() {}
1897 wxString
wxLongStringProperty::ValueToString( wxVariant
& value
,
1898 int WXUNUSED(argFlags
) ) const
1903 bool wxLongStringProperty::OnEvent( wxPropertyGrid
* propGrid
, wxWindow
* WXUNUSED(primary
),
1906 if ( propGrid
->IsMainButtonEvent(event
) )
1909 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
1911 wxString val1
= useValue
.GetString();
1912 wxString val_orig
= val1
;
1915 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1916 wxPropertyGrid::ExpandEscapeSequences(value
,val1
);
1918 value
= wxString(val1
);
1920 // Run editor dialog.
1921 if ( OnButtonClick(propGrid
,value
) )
1923 if ( !(m_flags
& wxPG_PROP_NO_ESCAPE
) )
1924 wxPropertyGrid::CreateEscapeSequences(val1
,value
);
1928 if ( val1
!= val_orig
)
1930 SetValueInEvent( val1
);
1938 bool wxLongStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
, wxString
& value
)
1940 return DisplayEditorDialog(this, propGrid
, value
);
1943 bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty
* prop
, wxPropertyGrid
* propGrid
, wxString
& value
)
1946 // launch editor dialog
1947 wxDialog
* dlg
= new wxDialog(propGrid
,-1,prop
->GetLabel(),wxDefaultPosition
,wxDefaultSize
,
1948 wxDEFAULT_DIALOG_STYLE
|wxRESIZE_BORDER
|wxCLIP_CHILDREN
);
1950 dlg
->SetFont(propGrid
->GetFont()); // To allow entering chars of the same set as the propGrid
1952 // Multi-line text editor dialog.
1953 #if !wxPG_SMALL_SCREEN
1954 const int spacing
= 8;
1956 const int spacing
= 4;
1958 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
1959 wxBoxSizer
* rowsizer
= new wxBoxSizer( wxHORIZONTAL
);
1960 wxTextCtrl
* ed
= new wxTextCtrl(dlg
,11,value
,
1961 wxDefaultPosition
,wxDefaultSize
,wxTE_MULTILINE
);
1963 rowsizer
->Add( ed
, 1, wxEXPAND
|wxALL
, spacing
);
1964 topsizer
->Add( rowsizer
, 1, wxEXPAND
, 0 );
1966 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
1967 buttonSizer
->AddButton(new wxButton(dlg
, wxID_OK
));
1968 buttonSizer
->AddButton(new wxButton(dlg
, wxID_CANCEL
));
1969 buttonSizer
->Realize();
1970 topsizer
->Add( buttonSizer
, 0,
1971 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxBOTTOM
|wxRIGHT
,
1974 dlg
->SetSizer( topsizer
);
1975 topsizer
->SetSizeHints( dlg
);
1977 #if !wxPG_SMALL_SCREEN
1978 dlg
->SetSize(400,300);
1980 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(prop
,dlg
->GetSize()) );
1983 int res
= dlg
->ShowModal();
1985 if ( res
== wxID_OK
)
1987 value
= ed
->GetValue();
1995 bool wxLongStringProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
1997 if ( variant
!= text
)
2005 #if wxUSE_EDITABLELISTBOX
2007 // -----------------------------------------------------------------------
2008 // wxPGArrayEditorDialog
2009 // -----------------------------------------------------------------------
2011 BEGIN_EVENT_TABLE(wxPGArrayEditorDialog
, wxDialog
)
2012 EVT_IDLE(wxPGArrayEditorDialog::OnIdle
)
2015 IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog
, wxDialog
)
2017 #include "wx/editlbox.h"
2018 #include "wx/listctrl.h"
2020 // -----------------------------------------------------------------------
2022 void wxPGArrayEditorDialog::OnIdle(wxIdleEvent
& event
)
2024 // Repair focus - wxEditableListBox has bitmap buttons, which
2025 // get focus, and lose focus (into the oblivion) when they
2026 // become disabled due to change in control state.
2028 wxWindow
* lastFocused
= m_lastFocused
;
2029 wxWindow
* focus
= ::wxWindow::FindFocus();
2031 // If last focused control became disabled, set focus back to
2032 // wxEditableListBox
2033 if ( lastFocused
&& focus
!= lastFocused
&&
2034 lastFocused
->GetParent() == m_elbSubPanel
&&
2035 !lastFocused
->IsEnabled() )
2037 m_elb
->GetListCtrl()->SetFocus();
2040 m_lastFocused
= focus
;
2045 // -----------------------------------------------------------------------
2047 wxPGArrayEditorDialog::wxPGArrayEditorDialog()
2053 // -----------------------------------------------------------------------
2055 void wxPGArrayEditorDialog::Init()
2057 m_lastFocused
= NULL
;
2058 m_hasCustomNewAction
= false;
2059 m_itemPendingAtIndex
= -1;
2062 // -----------------------------------------------------------------------
2064 wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow
*parent
,
2065 const wxString
& message
,
2066 const wxString
& caption
,
2073 Create(parent
,message
,caption
,style
,pos
,sz
);
2076 // -----------------------------------------------------------------------
2078 bool wxPGArrayEditorDialog::Create( wxWindow
*parent
,
2079 const wxString
& message
,
2080 const wxString
& caption
,
2085 // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
2086 // FIXME: This should be only a temporary fix.
2089 int useStyle
= wxCAPTION
;
2091 int useStyle
= style
;
2094 bool res
= wxDialog::Create(parent
, wxID_ANY
, caption
, pos
, sz
, useStyle
);
2096 SetFont(parent
->GetFont()); // To allow entering chars of the same set as the propGrid
2098 #if !wxPG_SMALL_SCREEN
2099 const int spacing
= 4;
2101 const int spacing
= 3;
2106 wxBoxSizer
* topsizer
= new wxBoxSizer( wxVERTICAL
);
2109 if ( message
.length() )
2110 topsizer
->Add( new wxStaticText(this,-1,message
),
2111 0, wxALIGN_LEFT
|wxALIGN_CENTRE_VERTICAL
|wxALL
, spacing
);
2113 m_elb
= new wxEditableListBox(this, wxID_ANY
, message
,
2120 // Populate the list box
2122 for ( unsigned int i
=0; i
<ArrayGetCount(); i
++ )
2123 arr
.push_back(ArrayGet(i
));
2124 m_elb
->SetStrings(arr
);
2126 // Connect event handlers
2128 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2130 but
= m_elb
->GetNewButton();
2131 m_elbSubPanel
= but
->GetParent();
2132 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2133 wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick
),
2136 but
= m_elb
->GetDelButton();
2137 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2138 wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick
),
2141 but
= m_elb
->GetUpButton();
2142 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2143 wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick
),
2146 but
= m_elb
->GetDownButton();
2147 but
->Connect(but
->GetId(), wxEVT_COMMAND_BUTTON_CLICKED
,
2148 wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick
),
2151 lc
->Connect(lc
->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT
,
2152 wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit
),
2155 topsizer
->Add( m_elb
, 1, wxEXPAND
, spacing
);
2157 // Standard dialog buttons
2158 wxStdDialogButtonSizer
* buttonSizer
= new wxStdDialogButtonSizer();
2159 buttonSizer
->AddButton(new wxButton(this, wxID_OK
));
2160 buttonSizer
->AddButton(new wxButton(this, wxID_CANCEL
));
2161 buttonSizer
->Realize();
2162 topsizer
->Add( buttonSizer
, 0,
2163 wxALIGN_RIGHT
|wxALIGN_CENTRE_VERTICAL
|wxALL
,
2168 SetSizer( topsizer
);
2169 topsizer
->SetSizeHints( this );
2171 #if !wxPG_SMALL_SCREEN
2172 if ( sz
.x
== wxDefaultSize
.x
&&
2173 sz
.y
== wxDefaultSize
.y
)
2174 SetSize( wxSize(275,360) );
2182 // -----------------------------------------------------------------------
2184 int wxPGArrayEditorDialog::GetSelection() const
2186 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2188 int index
= lc
->GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
2195 // -----------------------------------------------------------------------
2197 void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent
& event
)
2199 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2200 int newItemIndex
= lc
->GetItemCount() - 1;
2202 if ( m_hasCustomNewAction
)
2205 if ( OnCustomNewAction(&str
) )
2207 if ( ArrayInsert(str
, newItemIndex
) )
2209 lc
->InsertItem(newItemIndex
, str
);
2214 // Do *not* skip the event! We do not want the wxEditableListBox
2219 m_itemPendingAtIndex
= newItemIndex
;
2225 // -----------------------------------------------------------------------
2227 void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent
& event
)
2229 int index
= GetSelection();
2232 ArrayRemoveAt( index
);
2239 // -----------------------------------------------------------------------
2241 void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent
& event
)
2243 int index
= GetSelection();
2246 ArraySwap(index
-1,index
);
2253 // -----------------------------------------------------------------------
2255 void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent
& event
)
2257 wxListCtrl
* lc
= m_elb
->GetListCtrl();
2258 int index
= GetSelection();
2259 int lastStringIndex
= lc
->GetItemCount() - 1;
2260 if ( index
>= 0 && index
< lastStringIndex
)
2262 ArraySwap(index
, index
+1);
2269 // -----------------------------------------------------------------------
2271 void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent
& event
)
2273 wxString str
= event
.GetLabel();
2275 if ( m_itemPendingAtIndex
>= 0 )
2278 if ( ArrayInsert(str
, m_itemPendingAtIndex
) )
2284 // Editable list box doesn't really respect Veto(), but
2285 // it recognizes if no text was added, so we simulate
2287 event
.m_item
.SetText(wxEmptyString
);
2288 m_elb
->GetListCtrl()->SetItemText(m_itemPendingAtIndex
,
2296 // Change an existing item
2297 int index
= GetSelection();
2298 wxASSERT( index
!= wxNOT_FOUND
);
2299 if ( ArraySet(index
, str
) )
2308 #endif // wxUSE_EDITABLELISTBOX
2310 // -----------------------------------------------------------------------
2311 // wxPGArrayStringEditorDialog
2312 // -----------------------------------------------------------------------
2314 IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2316 BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog
, wxPGArrayEditorDialog
)
2319 // -----------------------------------------------------------------------
2321 wxString
wxPGArrayStringEditorDialog::ArrayGet( size_t index
)
2323 return m_array
[index
];
2326 size_t wxPGArrayStringEditorDialog::ArrayGetCount()
2328 return m_array
.size();
2331 bool wxPGArrayStringEditorDialog::ArrayInsert( const wxString
& str
, int index
)
2336 m_array
.Insert(str
,index
);
2340 bool wxPGArrayStringEditorDialog::ArraySet( size_t index
, const wxString
& str
)
2342 m_array
[index
] = str
;
2346 void wxPGArrayStringEditorDialog::ArrayRemoveAt( int index
)
2348 m_array
.RemoveAt(index
);
2351 void wxPGArrayStringEditorDialog::ArraySwap( size_t first
, size_t second
)
2353 wxString old_str
= m_array
[first
];
2354 wxString new_str
= m_array
[second
];
2355 m_array
[first
] = new_str
;
2356 m_array
[second
] = old_str
;
2359 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
2360 : wxPGArrayEditorDialog()
2365 void wxPGArrayStringEditorDialog::Init()
2367 m_pCallingClass
= NULL
;
2371 wxPGArrayStringEditorDialog::OnCustomNewAction(wxString
* resString
)
2373 return m_pCallingClass
->OnCustomStringEdit(m_parent
, *resString
);
2376 // -----------------------------------------------------------------------
2377 // wxArrayStringProperty
2378 // -----------------------------------------------------------------------
2380 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayStringProperty
, // Property name
2381 wxPGProperty
, // Property we inherit from
2382 wxArrayString
, // Value type name
2383 const wxArrayString
&, // Value type, as given in constructor
2384 TextCtrlAndButton
) // Initial editor
2386 wxArrayStringProperty::wxArrayStringProperty( const wxString
& label
,
2387 const wxString
& name
,
2388 const wxArrayString
& array
)
2389 : wxPGProperty(label
,name
)
2395 wxArrayStringProperty::~wxArrayStringProperty() { }
2397 void wxArrayStringProperty::OnSetValue()
2399 GenerateValueAsString();
2403 wxArrayStringProperty::ConvertArrayToString(const wxArrayString
& arr
,
2405 const wxUniChar
& delimiter
) const
2407 if ( delimiter
== '"' || delimiter
== '\'' )
2410 ArrayStringToString(*pString
,
2413 Escape
| QuoteStrings
);
2417 // Regular delimiter
2418 ArrayStringToString(*pString
,
2425 wxString
wxArrayStringProperty::ValueToString( wxVariant
& WXUNUSED(value
),
2426 int argFlags
) const
2429 // If this is called from GetValueAsString(), return cached string
2430 if ( argFlags
& wxPG_VALUE_IS_CURRENT
)
2435 wxArrayString arr
= m_value
.GetArrayString();
2437 ConvertArrayToString(arr
, &s
, m_delimiter
);
2441 // Converts wxArrayString to a string separated by delimeters and spaces.
2442 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
2445 wxArrayStringProperty::ArrayStringToString( wxString
& dst
,
2446 const wxArrayString
& src
,
2447 wxUniChar delimiter
, int flags
)
2453 unsigned int itemCount
= src
.size();
2457 if ( flags
& Escape
)
2460 pdr
= wxS("\\") + static_cast<wchar_t>(delimiter
);
2464 dst
.append( preas
);
2466 wxString
delimStr(delimiter
);
2468 for ( i
= 0; i
< itemCount
; i
++ )
2470 wxString
str( src
.Item(i
) );
2472 // Do some character conversion.
2473 // Converts \ to \\ and $delimiter to \$delimiter
2474 // Useful when quoting.
2475 if ( flags
& Escape
)
2477 str
.Replace( wxS("\\"), wxS("\\\\"), true );
2479 str
.Replace( preas
, pdr
, true );
2484 if ( i
< (itemCount
-1) )
2486 dst
.append( delimStr
);
2487 dst
.append( wxS(" ") );
2488 dst
.append( preas
);
2490 else if ( flags
& QuoteStrings
)
2491 dst
.append( delimStr
);
2495 void wxArrayStringProperty::GenerateValueAsString()
2497 wxArrayString arr
= m_value
.GetArrayString();
2498 ConvertArrayToString(arr
, &m_display
, m_delimiter
);
2501 // Default implementation doesn't do anything.
2502 bool wxArrayStringProperty::OnCustomStringEdit( wxWindow
*, wxString
& )
2507 wxPGArrayEditorDialog
* wxArrayStringProperty::CreateEditorDialog()
2509 return new wxPGArrayStringEditorDialog();
2512 bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid
* propGrid
,
2513 wxWindow
* WXUNUSED(primaryCtrl
),
2517 wxVariant useValue
= propGrid
->GetUncommittedPropertyValue();
2519 if ( !propGrid
->EditorValidate() )
2522 // Create editor dialog.
2523 wxPGArrayEditorDialog
* dlg
= CreateEditorDialog();
2524 #if wxUSE_VALIDATORS
2525 wxValidator
* validator
= GetValidator();
2526 wxPGInDialogValidator dialogValidator
;
2529 wxPGArrayStringEditorDialog
* strEdDlg
= wxDynamicCast(dlg
, wxPGArrayStringEditorDialog
);
2532 strEdDlg
->SetCustomButton(cbt
, this);
2534 dlg
->SetDialogValue( useValue
);
2535 dlg
->Create(propGrid
, wxEmptyString
, m_label
);
2537 #if !wxPG_SMALL_SCREEN
2538 dlg
->Move( propGrid
->GetGoodEditorDialogPosition(this,dlg
->GetSize()) );
2547 int res
= dlg
->ShowModal();
2549 if ( res
== wxID_OK
&& dlg
->IsModified() )
2551 wxVariant value
= dlg
->GetDialogValue();
2552 if ( !value
.IsNull() )
2554 wxArrayString actualValue
= value
.GetArrayString();
2556 ConvertArrayToString(actualValue
, &tempStr
, m_delimiter
);
2557 #if wxUSE_VALIDATORS
2558 if ( dialogValidator
.DoValidate(propGrid
, validator
,
2562 SetValueInEvent( actualValue
);
2579 bool wxArrayStringProperty::OnEvent( wxPropertyGrid
* propGrid
,
2583 if ( propGrid
->IsMainButtonEvent(event
) )
2584 return OnButtonClick(propGrid
,primary
,(const wxChar
*) NULL
);
2588 bool wxArrayStringProperty::StringToValue( wxVariant
& variant
,
2589 const wxString
& text
, int ) const
2593 if ( m_delimiter
== '"' || m_delimiter
== '\'' )
2596 WX_PG_TOKENIZER2_BEGIN(text
, m_delimiter
)
2598 // Need to replace backslashes with empty characters
2599 // (opposite what is done in ConvertArrayToString()).
2600 token
.Replace ( wxS("\\\\"), wxS("\\"), true );
2604 WX_PG_TOKENIZER2_END()
2608 // Regular delimiter
2609 WX_PG_TOKENIZER1_BEGIN(text
, m_delimiter
)
2611 WX_PG_TOKENIZER1_END()
2619 bool wxArrayStringProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
2621 if ( name
== wxPG_ARRAY_DELIMITER
)
2623 m_delimiter
= value
.GetChar();
2624 GenerateValueAsString();
2630 // -----------------------------------------------------------------------
2631 // wxPGInDialogValidator
2632 // -----------------------------------------------------------------------
2634 #if wxUSE_VALIDATORS
2635 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* propGrid
,
2636 wxValidator
* validator
,
2637 const wxString
& value
)
2642 wxTextCtrl
* tc
= m_textCtrl
;
2647 tc
= new wxTextCtrl( propGrid
, wxPG_SUBID_TEMP1
, wxEmptyString
,
2648 wxPoint(30000,30000));
2655 tc
->SetValue(value
);
2657 validator
->SetWindow(tc
);
2658 bool res
= validator
->Validate(propGrid
);
2663 bool wxPGInDialogValidator::DoValidate( wxPropertyGrid
* WXUNUSED(propGrid
),
2664 wxValidator
* WXUNUSED(validator
),
2665 const wxString
& WXUNUSED(value
) )
2671 // -----------------------------------------------------------------------
2673 #endif // wxUSE_PROPGRID